﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Threading;
using System.Windows.Input;
using System.Xml;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Shapes;
using System.Windows.Documents;
using System.Reflection;
using System.IO;
using System.Runtime.InteropServices;

namespace SystemHelperLibrary.WpfExt
{
	internal enum WM
	{
		WINDOWPOSCHANGING = 0x0046,
	}

	[Flags()]
	public enum SWP
	{
		Normal = 0x0,
		NoSize = 0x1,
		NoMove = 0x2,
	}

	[StructLayout(LayoutKind.Sequential)]
	internal struct WINDOWPOS
	{
		public IntPtr hwnd;
		public IntPtr hwndInsertAfter;
		public int x;
		public int y;
		public int cx;
		public int cy;
		public int flags;
	}

	public class WindowWithoutIconBase : Window
	{
		[DllImport("user32.dll")]
		static extern int GetWindowLong(IntPtr hwnd, int index);

		[DllImport("user32.dll")]
		static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);

		[DllImport("user32.dll")]
		static extern bool SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int width, int height, uint flags);

		[DllImport("user32.dll")]
		static extern IntPtr SendMessage(IntPtr hwnd, uint msg, IntPtr wParam, IntPtr lParam);

		const int GWL_EXSTYLE = -20;
		const int WS_EX_DLGMODALFRAME = 0x0001;
		const int SWP_NOSIZE = 0x0001;
		const int SWP_NOMOVE = 0x0002;
		const int SWP_NOZORDER = 0x0004;
		const int SWP_FRAMECHANGED = 0x0020;
		const uint WM_SETICON = 0x0080;

		public WindowWithoutIconBase()
		{
			this.SourceInitialized += new EventHandler(WindowWithoutIconBase_SourceInitialized);
		}

		void WindowWithoutIconBase_SourceInitialized(object sender, EventArgs e)
		{
			System.Windows.Interop.HwndSource hwndSource = System.Windows.Interop.HwndSource.FromVisual((Window)sender)
														as System.Windows.Interop.HwndSource;

			hwndSource.AddHook(DragHook);
		}

		private static IntPtr DragHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handeled)
		{
			switch ((WM)msg)
			{
				case WM.WINDOWPOSCHANGING:
					{
						WINDOWPOS pos = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS));
						if ((pos.flags & (int)SWP.NoMove) != 0)
						{
							return IntPtr.Zero;
						}

						Window wnd = (Window)System.Windows.Interop.HwndSource.FromHwnd(hwnd).RootVisual;
						if (wnd == null)
						{
							return IntPtr.Zero;
						}

						bool changedPos = false;

						// ***********************
						// Here you check the values inside the pos structure
						// if you want to override tehm just change the pos
						// structure and set changedPos to true
						// ***********************

						if (!changedPos)
						{
							return IntPtr.Zero;
						}

						Marshal.StructureToPtr(pos, lParam, true);
						handeled = true;
					}
					break;

				default:
					break;
			}

			return IntPtr.Zero;
		}

		protected override void OnSourceInitialized(EventArgs e)
		{
			base.OnSourceInitialized(e);
			// Get this window's handle

			IntPtr hwnd = new System.Windows.Interop.WindowInteropHelper(this).Handle;
			// Change the extended window style to not show a window icon
			int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
			SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_DLGMODALFRAME);

			// Update the window's non-client area to reflect the changes
			SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
		}
	}

	public static class FocusHelper
	{
		public static void DelayedFocus(this UIElement uiElement)
		{
			uiElement.Dispatcher.BeginInvoke(new Action(delegate
			{
				uiElement.Focusable = true;
				uiElement.Focus();
				Keyboard.Focus(uiElement);
			}), DispatcherPriority.Render);
		}

	}

	public static class RoutedEventHelper
	{
		internal static void RaiseEvent(DependencyObject target, RoutedEventArgs args)
		{
			if (target is UIElement)
			{
				(target as UIElement).RaiseEvent(args);
				return;
			}
			if (target is ContentElement)
			{
				(target as ContentElement).RaiseEvent(args);
			}
		}
		internal static void AddHandler(DependencyObject element, RoutedEvent routedEvent, Delegate handler)
		{
			UIElement uIElement = element as UIElement;
			if (uIElement != null)
			{
				uIElement.AddHandler(routedEvent, handler);
				return;
			}
			ContentElement contentElement = element as ContentElement;
			if (contentElement != null)
			{
				contentElement.AddHandler(routedEvent, handler);
			}
		}
		internal static void RemoveHandler(DependencyObject element, RoutedEvent routedEvent, Delegate handler)
		{
			UIElement uIElement = element as UIElement;
			if (uIElement != null)
			{
				uIElement.RemoveHandler(routedEvent, handler);
				return;
			}
			ContentElement contentElement = element as ContentElement;
			if (contentElement != null)
			{
				contentElement.RemoveHandler(routedEvent, handler);
			}
		}
	}

	public class ThreadingHelper
	{
		public static void InvokeSomeFunction(DependencyObject obj, Action action)
		{
			obj.Dispatcher.BeginInvoke(action, DispatcherPriority.Normal);
		}
	}

	/// <summary>      
	/// Extension methods for DataGrid      
	/// </summary> 
	public static class DataGridHelper
	{
		public static DataGridRow GetSelectedRow(this DataGrid grid)
		{
			return (DataGridRow)grid.ItemContainerGenerator.ContainerFromItem(grid.SelectedItem);
		}

		public static DataGridRow GetRow(this DataGrid grid, int index)
		{
			DataGridRow row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
			if (row == null)
			{
				// May be virtualized, bring into view and try again.
				grid.UpdateLayout();
				grid.ScrollIntoView(grid.Items[index]);
				row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
			}
			return row;
		}

		public static DataGridCell GetCell(this DataGrid grid, DataGridRow row, int column)
		{
			if (row != null)
			{
				DataGridCellsPresenter presenter = VisualTreeExt.VisualTreeHlpr.GetVisualChild<DataGridCellsPresenter>(row);

				if (presenter == null)
				{
					grid.ScrollIntoView(row, grid.Columns[column]);
					presenter = VisualTreeExt.VisualTreeHlpr.GetVisualChild<DataGridCellsPresenter>(row);
				}

				DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
				return cell;
			}
			return null;
		}

		public static DataGridCell GetCell(this DataGrid grid, int row, int column)
		{
			DataGridRow rowContainer = grid.GetRow(row);
			return grid.GetCell(rowContainer, column);
		}

	}

	public static class ListViewHelper
	{
		/// <summary>
		/// Select in ListView specify items
		/// </summary>
		/// <param name="listView"></param>
		/// <param name="indices"></param>
		public static void SelectListViewItems(this ListView listView, IEnumerable<Int32> indices)
		{
			if (listView.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
			{
				foreach (Int32 index in indices)
				{
					ListViewItem item = listView.ItemContainerGenerator.ContainerFromIndex(index) as ListViewItem;
					if (item != null)
					{
						Selector.SetIsSelected(item, true);
					}
					listView.Focus();
				}
			}
			else
			{
				listView.ItemContainerGenerator.StatusChanged += delegate { SelectListViewItems(listView, indices); };
			}
		}

		/// <summary>
		/// Получаем выбраные индексы
		/// </summary>
		/// <param name="listView"></param>
		/// <returns></returns>
		public static IEnumerable<Int32> GetSelectedIndices(this ListView listView)
		{
			return (from item in listView.SelectedItems.OfType<Object>()
					let container = listView.ItemContainerGenerator.ContainerFromItem(item) as ListViewItem
					where container != null
					select listView.ItemContainerGenerator.IndexFromContainer(container));
		}
	}

	/// <summary>
	/// 
	/// <example>
	/// <StackPanel>
	///<PasswordBox w:PasswordHelper.Attach="True" 
	///    w:PasswordHelper.Password="{Binding Text, ElementName=plain, Mode=TwoWay}" Width="130"/>
	///<TextBlock Padding="10,0" x:Name="plain" />
	///</StackPanel>
	/// </example>
	/// </summary>
	public static class PasswordHelper
	{
		public static readonly DependencyProperty PasswordProperty =
			DependencyProperty.RegisterAttached("Password",
			typeof(string), typeof(PasswordHelper),
			new FrameworkPropertyMetadata(string.Empty, OnPasswordPropertyChanged));

		public static readonly DependencyProperty AttachProperty =
			DependencyProperty.RegisterAttached("Attach",
			typeof(bool), typeof(PasswordHelper), new PropertyMetadata(false, Attach));

		private static readonly DependencyProperty IsUpdatingProperty =
		   DependencyProperty.RegisterAttached("IsUpdating", typeof(bool),
		   typeof(PasswordHelper));


		public static void SetAttach(DependencyObject dp, bool value)
		{
			dp.SetValue(AttachProperty, value);
		}

		public static bool GetAttach(DependencyObject dp)
		{
			return (bool)dp.GetValue(AttachProperty);
		}

		public static string GetPassword(DependencyObject dp)
		{
			return (string)dp.GetValue(PasswordProperty);
		}

		public static void SetPassword(DependencyObject dp, string value)
		{
			dp.SetValue(PasswordProperty, value);
		}

		private static bool GetIsUpdating(DependencyObject dp)
		{
			return (bool)dp.GetValue(IsUpdatingProperty);
		}

		private static void SetIsUpdating(DependencyObject dp, bool value)
		{
			dp.SetValue(IsUpdatingProperty, value);
		}

		private static void OnPasswordPropertyChanged(DependencyObject sender,
			DependencyPropertyChangedEventArgs e)
		{
			PasswordBox passwordBox = sender as PasswordBox;
			passwordBox.PasswordChanged -= PasswordChanged;

			if (!(bool)GetIsUpdating(passwordBox))
			{
				passwordBox.Password = (string)e.NewValue;
			}
			passwordBox.PasswordChanged += PasswordChanged;
		}

		private static void Attach(DependencyObject sender,
			DependencyPropertyChangedEventArgs e)
		{
			PasswordBox passwordBox = sender as PasswordBox;

			if (passwordBox == null)
				return;

			if ((bool)e.OldValue)
			{
				passwordBox.PasswordChanged -= PasswordChanged;
			}

			if ((bool)e.NewValue)
			{
				passwordBox.PasswordChanged += PasswordChanged;
			}
		}

		private static void PasswordChanged(object sender, RoutedEventArgs e)
		{
			PasswordBox passwordBox = sender as PasswordBox;
			SetIsUpdating(passwordBox, true);
			SetPassword(passwordBox, passwordBox.Password);
			SetIsUpdating(passwordBox, false);
		}
	}

	public class ThumbPointAdorner : Adorner, IDisposable
	{
		/// <summary>
		/// Initialize the ResizingAdorner.
		/// </summary>
		/// <param name="adornedElement"></param>
		public ThumbPointAdorner(UIElement adornedElement)
			: base(adornedElement)
		{
			m_visualChildren = new VisualCollection(this);

			if (adornedElement is Polyline)
				foreach (Point point in (adornedElement as Polyline).Points)
				{
					// Call a helper method to initialize the Thumbs 
					// with a customized cursors AND add handler for Thumb DragDelta event 
					Thumb newThumb = BuildThumbAdorner(point, Cursors.SizeNWSE);
					newThumb.DragDelta += new DragDeltaEventHandler(ThumbPointAdorner_OnDragDelta);
				}
		}

		private bool m_disposed = false;
		// Resizing adorner uses Thumbs for visual elements.   
		// The Thumbs have built-in mouse input handling. 
		private List<Thumb> m_thumbs = new List<Thumb>();
		// To store and manage the adorner's visual children. 
		private VisualCollection m_visualChildren;

		#region private methods


		// Handler for thumb dragging 
		void ThumbPointAdorner_OnDragDelta(object sender, DragDeltaEventArgs args)
		{
			FrameworkElement adornedElement = this.AdornedElement as FrameworkElement;
			Thumb movingThumb = sender as Thumb;

			if (adornedElement == null || movingThumb == null) return;
			FrameworkElement parentElement = adornedElement.Parent as FrameworkElement;

			// Ensure that the Width and Height are properly initialized after the resize. 
			EnforceSize(adornedElement);

			if (adornedElement is Polyline)
			{
				// TODO: WHY IS THIS NOT WORKING? 
				//Error     3       Cannot modify the return value of 'System.Windows.Media.PointCollection.this[int]'  
				//because it is not a variable       
				//update the Points property with PointsCollection which triggers rendering system to redraw the Polyline.  
				PointCollection clonedPoints = (adornedElement as Polyline).Points;
				Point point = clonedPoints[m_thumbs.IndexOf(movingThumb)];
				point.X += args.HorizontalChange;
				point.Y += args.VerticalChange;
				//clonedPoints[_thumbs.IndexOf(hitThumb)].X = clonedPoints[_thumbs.IndexOf(hitThumb)].X +  
				//                                            args.HorizontalChange; 
				//clonedPoints[_thumbs.IndexOf(hitThumb)].Y = clonedPoints[_thumbs.IndexOf(hitThumb)].Y + 
				//                                            args.VerticalChange; 

				(adornedElement as Polyline).Points = clonedPoints;
				InkCanvas.SetLeft(movingThumb, point.X);
				InkCanvas.SetTop(movingThumb, point.Y);
			}
		}
		#endregion private methods

		#region Adorner members

		// Override the VisualChildrenCount and GetVisualChild properties to interface with  
		// the adorner's visual collection. 
		protected override int VisualChildrenCount { get { return m_visualChildren.Count; } }
		protected override Visual GetVisualChild(int index) { return m_visualChildren[index]; }

		/// <summary>
		/// Arrange the Adorners.
		/// </summary>
		/// <param name="finalSize"></param>
		/// <returns></returns>

		protected override Size ArrangeOverride(Size finalSize)
		{
			// desiredWidth and desiredHeight are the width and height of the element that's being adorned.   
			// These will be used to place the ResizingAdorner at the corners of the adorned element.   
			double desiredWidth = AdornedElement.DesiredSize.Width;
			double desiredHeight = AdornedElement.DesiredSize.Height;
			// adornerWidth & adornerHeight are used for placement as well. 
			double adornerWidth = this.DesiredSize.Width;
			double adornerHeight = this.DesiredSize.Height;

			foreach (Thumb thumb in m_thumbs)
			{
				thumb.Arrange(new Rect(-adornerWidth / 2, -adornerHeight / 2, adornerWidth, adornerHeight));
			}
			// Return the final size. 
			return finalSize;
		}

		// Helper method to instantiate the corner Thumbs, set the Cursor property,  
		// set some appearance properties, and add the elements to the visual tree. 
		private Thumb BuildThumbAdorner(Point point, Cursor customizedCursor)
		{
			if (point == null) return default(Thumb);

			Thumb thumb = new Thumb();

			// Set some arbitrary visual characteristics. 
			thumb.Cursor = customizedCursor;
			thumb.Height = thumb.Width = 10;
			thumb.Opacity = 0.40;
			thumb.Background = new SolidColorBrush(Colors.MediumBlue);
			InkCanvas.SetLeft(thumb, point.X);
			InkCanvas.SetTop(thumb, point.Y);

			m_visualChildren.Add(thumb);
			m_thumbs.Add(thumb);

			return thumb;
		}

		// This method ensures that the Widths and Heights are initialized.  Sizing to content produces 
		// Width and Height values of Double.NaN.  Because this Adorner explicitly resizes, the Width and Height 
		// need to be set first.  It also sets the maximum size of the adorned element. 
		void EnforceSize(FrameworkElement adornedElement)
		{
			if (adornedElement.Width.Equals(Double.NaN))
				adornedElement.Width = adornedElement.DesiredSize.Width;
			if (adornedElement.Height.Equals(Double.NaN))
				adornedElement.Height = adornedElement.DesiredSize.Height;

			FrameworkElement parent = adornedElement.Parent as FrameworkElement;
			if (parent != null)
			{
				adornedElement.MaxHeight = parent.ActualHeight;
				adornedElement.MaxWidth = parent.ActualWidth;
			}
		}

		#endregion Adorner members


		public void Dispose()
		{
			if (!m_disposed)
			{
				m_disposed = true;
				this.m_thumbs.Clear();
				m_thumbs = null;
				m_visualChildren.Clear();
				m_visualChildren = null;
				GC.Collect();
				GC.SuppressFinalize(this);
			}
		}
	}

	public static class WindowHelper
	{
		public static IEnumerable<string> WindowNames
		{
			get
			{
				IEnumerable<string> ieWindowNames = null;
				Assembly asm = Assembly.GetExecutingAssembly();

				ieWindowNames = from types in asm.GetTypes()
								where types.BaseType.Name == "Window"
								orderby types.Name
								select types.Name;

				return ieWindowNames;
			}
		}

		public static bool? ShowWindowByName(string strWindowName, bool fShowDialog)
		{
			if (string.IsNullOrEmpty(strWindowName))
				return null;

			Assembly asm = Assembly.GetExecutingAssembly();
			string strFullyQualifiedName = asm.GetName().Name + "." + strWindowName;

			object obj = asm.CreateInstance(strFullyQualifiedName);

			Window win = obj as Window;
			if (win == null)
				return null;

			if (fShowDialog)
			{
				win.ShowDialog();
				return win.DialogResult;
			}
			else
			{
				win.Show();
				return null;
			}
		}

		public static Window WindowByName(string strWindowName)
		{
			if (string.IsNullOrEmpty(strWindowName))
				return null;

			Assembly asm = Assembly.GetExecutingAssembly();
			string strFullyQualifiedName = asm.GetName().Name + "." + strWindowName;
			object obj = asm.CreateInstance(strFullyQualifiedName);
			if (obj != null)
				return obj as Window;
			else
				return null;
		}

	}

	namespace BindingExt
	{
		using System.Windows.Data;
		using System.ComponentModel;
		using System.Globalization;


		public static class BindingHelper
		{
			public static void UpdateBindingSources(DependencyObject obj,
											params DependencyProperty[] properties)
			{
				foreach (DependencyProperty depProperty in properties)
				{
					//check whether the submitted object provides a bound property
					//that matches the property parameters
					BindingExpression be = BindingOperations.GetBindingExpression(obj, depProperty);
					if (be != null) be.UpdateSource();
				}

				int count = VisualTreeHelper.GetChildrenCount(obj);
				for (int i = 0; i < count; i++)
				{
					//process child items recursively
					DependencyObject childObject = VisualTreeHelper.GetChild(obj, i);
					UpdateBindingSources(childObject, properties);
				}
			}
		}

		/// <summary>
		/// A base class for custom markup extension which provides properties
		/// that can be found on regular <see cref="Binding"/> markup extension.<br/>
		/// See: http://www.hardcodet.net/2008/04/wpf-custom-binding-class 
		/// </summary>
		[MarkupExtensionReturnType(typeof(object))]
		public abstract class BindingDecoratorBase : MarkupExtension
		{
			/// <summary>
			/// The decorated binding class.
			/// </summary>
			private Binding binding = new Binding();


			//check documentation of the Binding class for property information

			#region properties

			/// <summary>
			/// The decorated binding class.
			/// </summary>
			[Browsable(false)]
			public Binding Binding
			{
				get { return binding; }
				set { binding = value; }
			}


			[DefaultValue(null)]
			public object AsyncState
			{
				get { return binding.AsyncState; }
				set { binding.AsyncState = value; }
			}

			[DefaultValue(false)]
			public bool BindsDirectlyToSource
			{
				get { return binding.BindsDirectlyToSource; }
				set { binding.BindsDirectlyToSource = value; }
			}

			[DefaultValue(null)]
			public IValueConverter Converter
			{
				get { return binding.Converter; }
				set { binding.Converter = value; }
			}

			[DefaultValue(null)]
			public object TargetNullValue
			{
				get { return binding.TargetNullValue; }
				set { binding.TargetNullValue = value; }
			}

			[TypeConverter(typeof(CultureInfoIetfLanguageTagConverter)), DefaultValue(null)]
			public CultureInfo ConverterCulture
			{
				get { return binding.ConverterCulture; }
				set { binding.ConverterCulture = value; }
			}

			[DefaultValue(null)]
			public object ConverterParameter
			{
				get { return binding.ConverterParameter; }
				set { binding.ConverterParameter = value; }
			}

			[DefaultValue(null)]
			public string ElementName
			{
				get { return binding.ElementName; }
				set { binding.ElementName = value; }
			}

			[DefaultValue(null)]
			public object FallbackValue
			{
				get { return binding.FallbackValue; }
				set { binding.FallbackValue = value; }
			}

			[DefaultValue(false)]
			public bool IsAsync
			{
				get { return binding.IsAsync; }
				set { binding.IsAsync = value; }
			}

			[DefaultValue(BindingMode.Default)]
			public BindingMode Mode
			{
				get { return binding.Mode; }
				set { binding.Mode = value; }
			}

			[DefaultValue(false)]
			public bool NotifyOnSourceUpdated
			{
				get { return binding.NotifyOnSourceUpdated; }
				set { binding.NotifyOnSourceUpdated = value; }
			}

			[DefaultValue(false)]
			public bool NotifyOnTargetUpdated
			{
				get { return binding.NotifyOnTargetUpdated; }
				set { binding.NotifyOnTargetUpdated = value; }
			}

			[DefaultValue(false)]
			public bool NotifyOnValidationError
			{
				get { return binding.NotifyOnValidationError; }
				set { binding.NotifyOnValidationError = value; }
			}

			[DefaultValue(null)]
			public PropertyPath Path
			{
				get { return binding.Path; }
				set { binding.Path = value; }
			}

			[DefaultValue(null)]
			public RelativeSource RelativeSource
			{
				get { return binding.RelativeSource; }
				set { binding.RelativeSource = value; }
			}

			[DefaultValue(null)]
			public object Source
			{
				get { return binding.Source; }
				set { binding.Source = value; }
			}

			[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
			public UpdateSourceExceptionFilterCallback UpdateSourceExceptionFilter
			{
				get { return binding.UpdateSourceExceptionFilter; }
				set { binding.UpdateSourceExceptionFilter = value; }
			}

			[DefaultValue(UpdateSourceTrigger.Default)]
			public UpdateSourceTrigger UpdateSourceTrigger
			{
				get { return binding.UpdateSourceTrigger; }
				set { binding.UpdateSourceTrigger = value; }
			}

			[DefaultValue(false)]
			public bool ValidatesOnDataErrors
			{
				get { return binding.ValidatesOnDataErrors; }
				set { binding.ValidatesOnDataErrors = value; }
			}

			[DefaultValue(false)]
			public bool ValidatesOnExceptions
			{
				get { return binding.ValidatesOnExceptions; }
				set { binding.ValidatesOnExceptions = value; }
			}

			[DefaultValue(null)]
			public string XPath
			{
				get { return binding.XPath; }
				set { binding.XPath = value; }
			}

			[DefaultValue(null)]
			public ICollection<ValidationRule> ValidationRules
			{
				get { return binding.ValidationRules; }
			}

			[DefaultValue(null)]
			public string StringFormat
			{
				get { return binding.StringFormat; }
				set { binding.StringFormat = value; }
			}

			[DefaultValue("")]
			public string BindingGroupName
			{
				get { return binding.BindingGroupName; }
				set { binding.BindingGroupName = value; }
			}



			#endregion



			/// <summary>
			/// This basic implementation just sets a binding on the targeted
			/// <see cref="DependencyObject"/> and returns the appropriate
			/// <see cref="BindingExpressionBase"/> instance.<br/>
			/// All this work is delegated to the decorated <see cref="Binding"/>
			/// instance.
			/// </summary>
			/// <returns>
			/// The object value to set on the property where the extension is applied. 
			/// In case of a valid binding expression, this is a <see cref="BindingExpressionBase"/>
			/// instance.
			/// </returns>
			/// <param name="provider">Object that can provide services for the markup
			/// extension.</param>
			public override object ProvideValue(IServiceProvider provider)
			{
				//create a binding and associate it with the target
				return binding.ProvideValue(provider);
			}



			/// <summary>
			/// Validates a service provider that was submitted to the <see cref="ProvideValue"/>
			/// method. This method checks whether the provider is null (happens at design time),
			/// whether it provides an <see cref="IProvideValueTarget"/> service, and whether
			/// the service's <see cref="IProvideValueTarget.TargetObject"/> and
			/// <see cref="IProvideValueTarget.TargetProperty"/> properties are valid
			/// <see cref="DependencyObject"/> and <see cref="DependencyProperty"/>
			/// instances.
			/// </summary>
			/// <param name="provider">The provider to be validated.</param>
			/// <param name="target">The binding target of the binding.</param>
			/// <param name="dp">The target property of the binding.</param>
			/// <returns>True if the provider supports all that's needed.</returns>
			protected virtual bool TryGetTargetItems(IServiceProvider provider, out DependencyObject target, out DependencyProperty dp)
			{
				target = null;
				dp = null;
				if (provider == null) return false;

				//create a binding and assign it to the target
				IProvideValueTarget service = (IProvideValueTarget)provider.GetService(typeof(IProvideValueTarget));
				if (service == null) return false;

				//we need dependency objects / properties
				target = service.TargetObject as DependencyObject;
				dp = service.TargetProperty as DependencyProperty;
				return target != null && dp != null;
			}

		}

	}

	namespace DialogsExt
	{
		/// <summary>
		/// Provides convenience methods to display message boxes. In order to set
		/// the title of the message box, provide the class with a resolver method
		/// through <see cref="SetDialogTitleQuery"/>.
		/// </summary>
		public static class Dialogs
		{
			#region dialog title
			/// <summary>
			/// Resolves the application's name at runtime. Returns an empty
			/// string by default.
			/// </summary>
			private static Func<string> TitleQuery = () => String.Empty;

			/// <summary>
			/// Sets a function that resolves the application's name at runtime.
			/// </summary>
			/// <param name="query">A function that can be used to resolve the
			/// dialog title at runtime.</param>
			/// <exception cref="ArgumentNullException">If <paramref name="query"/>
			/// is a null reference.</exception>
			public static void SetDialogTitleQuery(Func<string> query)
			{
				if (query == null) throw new ArgumentNullException("query");
				TitleQuery = query;
			}

			/// <summary>
			/// Gets the title that is used when displaying a dialog on the UI.
			/// This property returns an empty string if no query function
			/// was assigned through <see cref="SetDialogTitleQuery"/>.
			/// </summary>
			public static string DialogTitle
			{
				get { return TitleQuery(); }
			}
			#endregion

			/// <summary>
			/// Displays an error dialog with a given message.
			/// </summary>
			/// <param name="message">The message to be displayed.</param>
			public static void ShowError(string message)
			{
				ShowMessage(message, MessageBoxImage.Error);
			}

			/// <summary>
			/// Displays an error dialog with a given message.
			/// </summary>
			/// <param name="message">The message to be displayed.</param>
			public static void ShowInformation(string message)
			{
				ShowMessage(message, MessageBoxImage.Information);
			}

			/// <summary>
			/// Displays an error dialog with a given message.
			/// </summary>
			/// <param name="message">The message to be displayed.</param>
			public static void ShowWarning(string message)
			{
				ShowMessage(message, MessageBoxImage.Warning);
			}

			/// <summary>
			/// Displays an error dialog with a given message and icon.
			/// </summary>
			/// <param name="message">The message to be displayed.</param>
			/// <param name="icon">The icon to be displayed with the message.</param>
			public static void ShowMessage(string message, MessageBoxImage icon)
			{
				MessageBox.Show(message, DialogTitle, MessageBoxButton.OK, icon);
			}

			/// <summary>
			/// Displays an OK / Cancel dialog and returns the user input.
			/// </summary>
			/// <param name="message">The message to be displayed.</param>
			/// <param name="icon">The icon to be displayed.</param>
			/// <returns>User selection.</returns>
			public static MessageBoxResult ShowOkCancel(string message, MessageBoxImage icon)
			{
				return MessageBox.Show(message, DialogTitle, MessageBoxButton.OKCancel, icon);
			}

			/// <summary>
			/// Displays a Yes/No dialog and returns the user input.
			/// </summary>
			/// <param name="message">The message to be displayed.</param>
			/// <param name="icon">The icon to be displayed.</param>
			/// <returns>User selection.</returns>
			public static MessageBoxResult ShowYesNo(string message, MessageBoxImage icon)
			{
				return MessageBox.Show(message, DialogTitle, MessageBoxButton.YesNo, icon);
			}

			/// <summary>
			/// Displays an Yes / No / Cancel dialog and returns the user input.
			/// </summary>
			/// <param name="message">The message to be displayed.</param>
			/// <param name="icon">The icon to be displayed.</param>
			/// <returns>User selection.</returns>
			public static MessageBoxResult ShowYesNoCancel(string message, MessageBoxImage icon)
			{
				return MessageBox.Show(message, DialogTitle, MessageBoxButton.YesNoCancel, icon);
			}
		}
	}

	namespace DependencyExt
	{
		public static class DependencyPropHelper
		{
			public static DependencyProperty Register<TElement, TProperty>(string name, TProperty defaultValue, Action<TElement, TProperty, TProperty> changeHandler = null)
				where TElement : DependencyObject
			{
				PropertyMetadata metadata; if (changeHandler == null)
				{ metadata = new PropertyMetadata(defaultValue); }
				else
				{
					metadata = new PropertyMetadata(defaultValue, GetPropertyChangedCallback(changeHandler));
				}

				return DependencyProperty.Register(name, typeof(TProperty), typeof(TElement), metadata);
			}

			public static DependencyProperty Register<TElement, TProperty>(string name, Action<TElement, TProperty, TProperty> changeHandler = null)
				where TElement : DependencyObject
			{
				PropertyMetadata metadata; if (changeHandler == null)
				{ metadata = null; }
				else
				{
					metadata = new PropertyMetadata(GetPropertyChangedCallback(changeHandler));
				}
				return DependencyProperty.Register(name, typeof(TProperty), typeof(TElement), metadata);
			}

			public static DependencyProperty RegisterAttached<TOwner, TTarget, TProperty>(string name, Action<TTarget, TProperty, TProperty> changeHandler = null) where TTarget :
				DependencyObject
			{
				PropertyMetadata metadata; if
					(changeHandler == null) { metadata = null; }
				else
				{
					metadata = new PropertyMetadata(GetPropertyChangedCallback(changeHandler));
				}
				return DependencyProperty.RegisterAttached(name, typeof(TProperty), typeof(TOwner), metadata);
			}

			private static PropertyChangedCallback GetPropertyChangedCallback<TElement, TProperty>(Action<TElement, TProperty, TProperty> handler) where TElement : DependencyObject
			{
				return new PropertyChangedCallback((element, args) =>
				{
					handler((TElement)element, (TProperty)args.NewValue, (TProperty)args.OldValue);
				});
			}
		}
	}

	namespace ConvertersExt
	{
		using System.Windows.Data;
		using System.Globalization;

		/// <summary>
		/// A base converter class which derives from <see cref="MarkupExtension"/>
		/// in order to simplify declaration in XAML.
		/// </summary>
		public abstract class ConverterExtension : MarkupExtension, IValueConverter
		{
			/// <summary>
			/// Gets a converter instance.
			/// </summary>
			public override object ProvideValue(IServiceProvider serviceProvider)
			{
				return this;
			}

			/// <summary>
			/// Converts a value. 
			/// </summary>
			/// <returns>
			/// A converted value. If the method returns null, the valid null value is used.
			/// </returns>
			/// <param name="value">The value produced by the binding source.
			/// </param>
			/// <param name="targetType">The type of the binding target property.
			/// </param>
			/// <param name="parameter">The converter parameter to use.
			/// </param>
			/// <param name="culture">The culture to use in the converter.
			/// </param>
			public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture);


			/// <summary>
			/// Converts a value. The default implementation throws a <see cref="NotSupportedException"/>,
			/// indicating that only one-way conversions are supported.
			/// </summary>
			/// <returns>
			/// A converted value. If the method returns null, the valid null value is used.
			/// </returns>
			/// <param name="value">The value that is produced by the binding target.
			/// </param>
			/// <param name="targetType">The type to convert to.
			/// </param>
			/// <param name="parameter">The converter parameter to use.
			/// </param>
			/// <param name="culture">The culture to use in the converter.
			/// </param>
			public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
			{
				throw new NotSupportedException("This converter supports only one-way conversion.");
			}
		}

		/// <summary>
		/// Converts a boolean value into a <see cref="Visibility"/>
		/// flag, optionally inverted by setting the parameter
		/// to an arbitrary value. If no parameter is being set,
		/// a boolean value of True is being converted to
		/// <see cref="Visibility.Visible"/>, while a false value
		/// will result in <see cref="Visibility.Collapsed"/>.
		/// </summary>
		[ValueConversion(typeof(bool), typeof(Visibility))]
		public class BoolToVisibilityConverter : ConverterExtension
		{
			/// <summary>
			/// Collapses an item if the submitted value is not true.
			/// </summary>
			public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
			{
				bool status = (bool?)value ?? false;
				//invert the parameter if it's anything but null
				if (parameter != null) status = !status;

				return status ? Visibility.Visible : Visibility.Collapsed;
			}

			public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
			{
				Visibility visiblity = (Visibility)value;
				return visiblity == Visibility.Visible;
			}
		}

		/// <summary>
		/// This converter is used to check if a value is of type string.Empty..
		/// </summary>
		[ValueConversion(typeof(string), typeof(bool))]
		public class IsEmptyStringConverter : ConverterExtension
		{
			/// <summary>
			/// Checks whether the value is <see cref="String.Empty"/>.
			/// </summary>
			public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
			{
				string s = value as string;
				return (s == string.Empty);
			}
		}

		/// <summary>
		/// Returns true if the input value is not null.
		/// </summary>
		[ValueConversion(typeof(object), typeof(bool))]
		public class IsNotNullConverter : ConverterExtension
		{
			public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
			{
				return value != null;
			}
		}

		/// <summary>
		/// Converts an object into a <see cref="Visibility"/>
		/// flag, optionally inverted by setting the parameter
		/// to an arbitrary value. Without inversion, a null parameter
		/// results in <see cref="Visibility.Collapsed"/> while and
		/// set value returns <see cref="Visibility.Visible"/>.
		/// </summary>
		[ValueConversion(typeof(object), typeof(Visibility))]
		public class NullToVisibilityConverter : ConverterExtension
		{
			/// <summary>
			/// Collapses an item if the submitted value is not true.
			/// </summary>
			/// <param name="value"></param>
			/// <param name="targetType"></param>
			/// <param name="parameter"></param>
			/// <param name="culture"></param>
			/// <returns></returns>
			public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
			{
				if (parameter != null)
				{
					return value == null ? Visibility.Visible : Visibility.Collapsed;
				}
				else
				{
					return value == null ? Visibility.Collapsed : Visibility.Visible;
				}
			}

			public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
			{
				Visibility visiblity = (Visibility)value;
				return visiblity == Visibility.Visible;
			}
		}

		/// <summary>
		/// Returns white-space characters around a given string.
		/// </summary>
		[ValueConversion(typeof(string), typeof(string))]
		public class TrimConverter : ConverterExtension
		{
			public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
			{
				string val = value as string;
				return val == null ? value : val.Trim();
			}
		}
	}

	namespace ControlsExt
	{
		using System.Collections.Specialized;
		using System.ComponentModel;
		using System.Collections;
		using System.Windows.Data;

		public class SortListView : ListView
		{
			private RoutedEventHandler _headerClickHandler;
			private ListSortDirection _lastDirection;
			public static readonly DependencyProperty DefaultItemsContainerStyleProperty;

			public Style DefaultItemsContainerStyle
			{
				get
				{
					return (Style)base.GetValue(SortListView.DefaultItemsContainerStyleProperty);
				}
				set
				{
					base.SetValue(SortListView.DefaultItemsContainerStyleProperty, value);
				}
			}

			static SortListView()
			{
				SortListView.DefaultItemsContainerStyleProperty = DependencyProperty.Register("DefaultItemsContainerStyle", typeof(Style), typeof(SortListView), new UIPropertyMetadata(null, delegate(DependencyObject s, DependencyPropertyChangedEventArgs e)
				{
					SortListView sortListView = s as SortListView;
					sortListView.ItemContainerStyle = (e.NewValue as Style);
				}
				));
				FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(SortListView), new FrameworkPropertyMetadata(typeof(SortListView)));
			}

			public SortListView()
			{
				this._headerClickHandler = new RoutedEventHandler(this.GridViewColumnHeader_Click);
			}

			public override void EndInit()
			{
				base.EndInit();
				GridView gridView = base.View as GridView;
				if (gridView != null)
				{
					gridView.Columns.CollectionChanged += new NotifyCollectionChangedEventHandler(this.GridViewColumns_CollectionChanged);
				}
			}
			private void GridViewColumns_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
			{
				if (e.Action == NotifyCollectionChangedAction.Add)
				{
					IEnumerator enumerator = e.NewItems.GetEnumerator();
					try
					{
						while (enumerator.MoveNext())
						{
							object current = enumerator.Current;
							GridViewColumnHeader gridViewColumnHeader = this.GetGridViewColumnHeader(current);
							if (gridViewColumnHeader != null)
							{
								gridViewColumnHeader.Click += this._headerClickHandler;
							}
						}
						return;
					}
					finally
					{
						IDisposable disposable = enumerator as IDisposable;
						if (disposable != null)
						{
							disposable.Dispose();
						}
					}
				}
				if (e.Action == NotifyCollectionChangedAction.Remove)
				{
					IEnumerator enumerator2 = e.OldItems.GetEnumerator();
					try
					{
						while (enumerator2.MoveNext())
						{
							object current2 = enumerator2.Current;
							GridViewColumnHeader gridViewColumnHeader2 = this.GetGridViewColumnHeader(current2);
							if (gridViewColumnHeader2 != null)
							{
								gridViewColumnHeader2.Click -= this._headerClickHandler;
							}
						}
					}
					finally
					{
						IDisposable disposable2 = enumerator2 as IDisposable;
						if (disposable2 != null)
						{
							disposable2.Dispose();
						}
					}
				}
			}

			private GridViewColumnHeader GetGridViewColumnHeader(object gridViewColumn)
			{
				GridViewColumn gridViewColumn2 = gridViewColumn as GridViewColumn;
				if (gridViewColumn2 != null)
				{
					return gridViewColumn2.Header as GridViewColumnHeader;
				}
				return null;
			}

			private void GridViewColumnHeader_Click(object sender, RoutedEventArgs e)
			{
				GridViewColumnHeader gridViewColumnHeader = e.OriginalSource as GridViewColumnHeader;
				if (gridViewColumnHeader != null && gridViewColumnHeader.Role != GridViewColumnHeaderRole.Padding)
				{
					if (this._lastDirection == ListSortDirection.Ascending)
					{
						this._lastDirection = ListSortDirection.Descending;
					}
					else
					{
						this._lastDirection = ListSortDirection.Ascending;
					}
					this.Sort(gridViewColumnHeader.Name, this._lastDirection);
				}
			}

			private void Sort(string sortBy, ListSortDirection direction)
			{
				ICollectionView defaultView = CollectionViewSource.GetDefaultView(base.ItemsSource);
				defaultView.SortDescriptions.Clear();
				SortDescription item = new SortDescription(sortBy, direction);
				defaultView.SortDescriptions.Add(item);
				defaultView.Refresh();
			}
		}
	}

	namespace ImageExt
	{
		using System.Windows.Media.Imaging;

		public static class ImageExtension
		{
			public static byte[] GetJPGFromImageControl(BitmapImage imageC)
			{
				using (MemoryStream memStream = new MemoryStream())
				{
					JpegBitmapEncoder encoder = new JpegBitmapEncoder();
					encoder.Frames.Add(BitmapFrame.Create(imageC));
					encoder.Save(memStream);
					return memStream.GetBuffer();
				}
			}

			public static System.Windows.Media.EllipseGeometry ClipImage(string source)
			{
				// Create a BitmapImage
				BitmapImage bmpImage = new BitmapImage();
				bmpImage.BeginInit();
				bmpImage.UriSource = new Uri(source, UriKind.RelativeOrAbsolute);
				bmpImage.EndInit();

				// Clipped Image
				System.Windows.Controls.Image clippedImage = new System.Windows.Controls.Image();
				clippedImage.Source = bmpImage;
				System.Windows.Media.EllipseGeometry clipGeometry = new System.Windows.Media.EllipseGeometry(new System.Windows.Point(150, 160), 120, 120);
				clippedImage.Clip = clipGeometry;

				return clipGeometry;
			}

			public static BitmapImage GetBitmapImage(byte[] data)
			{
				using (MemoryStream strm = new MemoryStream(data))
				{
					if (strm.CanSeek)
						strm.Seek(0, SeekOrigin.Begin);
					System.Drawing.Image img = System.Drawing.Image.FromStream(strm);
					BitmapImage bi = new BitmapImage();
					bi.BeginInit();
					using (MemoryStream ms = new MemoryStream())
					{
						img.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
						ms.Seek(0, SeekOrigin.Begin);
						bi.StreamSource = ms;
						bi.EndInit();
					}
					return bi;
				}
			}

			public static void SaveToBmp(FrameworkElement visual, string fileName)
			{
				var encoder = new BmpBitmapEncoder();
				SaveUsingEncoder(visual, fileName, encoder);
			}

			internal static void SaveToPng(FrameworkElement visual, string fileName)
			{
				var encoder = new PngBitmapEncoder();
				SaveUsingEncoder(visual, fileName, encoder);
			}

			internal static void SaveUsingEncoder(FrameworkElement visual, string fileName, BitmapEncoder encoder)
			{
				RenderTargetBitmap bitmap = new RenderTargetBitmap((int)visual.ActualWidth, (int)visual.ActualHeight,
																	96, 96, PixelFormats.Pbgra32);
				bitmap.Render(visual);
				BitmapFrame frame = BitmapFrame.Create(bitmap);
				encoder.Frames.Add(frame);
				using (var stream = File.Create(fileName))
				{
					encoder.Save(stream);
				}
			}
		}
	}

	namespace MVVMExt
	{
		using System.Diagnostics;
		using System.ComponentModel;
		using System.Collections.ObjectModel;
		using System.Collections.Specialized;

		public class RelayCommand : ICommand
		{
			readonly Action<object> _execute;
			readonly Predicate<object> _canExecute;

			public RelayCommand(Action<object> execute)
				: this(execute, null)
			{
			}

			public RelayCommand(Action<object> execute, Predicate<object> canExecute)
			{
				if (execute == null)
					throw new ArgumentNullException("execute");

				_execute = execute;
				_canExecute = canExecute;
			}

			#region ICommand Members

			[DebuggerStepThrough]
			public bool CanExecute(object parameter)
			{
				return _canExecute == null ? true : _canExecute(parameter);
			}

			public event EventHandler CanExecuteChanged
			{
				add { CommandManager.RequerySuggested += value; }
				remove { CommandManager.RequerySuggested -= value; }
			}

			public void Execute(object parameter)
			{
				_execute(parameter);
			}
			#endregion // ICommand Members
		}

		public class ViewModelBase : INotifyPropertyChanged
		{
			public event PropertyChangedEventHandler PropertyChanged;

			public EventHandler RequestClose;

			protected bool ThrowOnInvalidPropertyName;
			protected ObservableCollection<ViewModelBase> m_views;
			protected Dispatcher m_dispatcher;

			public virtual ObservableCollection<ViewModelBase> Workspaces
			{
				get
				{
					if (m_views == null)
					{
						m_views = new ObservableCollection<ViewModelBase>();
						m_views.CollectionChanged += this.OnWorkspacesChanged;
					}
					return m_views;
				}
			}

			public ViewModelBase()
			{
				ThrowOnInvalidPropertyName = false;
				SaveViewCommand = new RoutedCommand("SaveViewCommand", typeof(ViewModelBase));
			}

			public ViewModelBase(Dispatcher disp)
				: this()
			{
				m_dispatcher = disp;
			}

			public RoutedCommand SaveViewCommand
			{
				get;
				private set;
			}

			protected RelayCommand m_CloseCommand;
			public ICommand CloseCommand
			{
				get
				{
					m_CloseCommand = m_CloseCommand ?? new RelayCommand(param1 => CloseExecute());
					return m_CloseCommand;
				}
			}

			protected virtual void CloseExecute()
			{
				var wind = Application.Current.MainWindow;

				int count = Application.Current.Windows.Count;
				foreach (Window w in Application.Current.Windows)
				{
					if (w.Title != "File Explorer")
					{
						w.Focus();
						w.Close();
					}
				}
				string name = wind.Title;
				if (name.ToLower().Contains("f"))
					wind.Close();
			}

			protected virtual void OnPropertyChanged(string propertyName)
			{
				this.VerifyPropertyName(propertyName);

				PropertyChangedEventHandler handler = System.Threading.Interlocked.CompareExchange(ref this.PropertyChanged, null, null);
				if (handler != null)
				{

					handler(this, new PropertyChangedEventArgs(propertyName));
				}
			}

			protected virtual void OnWorkspacesChanged(object sender, NotifyCollectionChangedEventArgs e)
			{
				if (e.NewItems != null && e.NewItems.Count != 0)
					foreach (ViewModelBase workspace in e.NewItems)
						workspace.RequestClose += this.OnWorkspaceRequestClose;

				if (e.OldItems != null && e.OldItems.Count != 0)
					foreach (ViewModelBase workspace in e.OldItems)
						workspace.RequestClose -= this.OnWorkspaceRequestClose;
			}

			protected virtual void OnWorkspaceRequestClose(object sender, EventArgs e)
			{
				this.Workspaces.Remove(sender as ViewModelBase);
			}

			[Conditional("DEBUG")]
			[DebuggerStepThrough]
			public void VerifyPropertyName(string propertyName)
			{
				// Verify that the property name matches a real,  
				// public, instance property on this object.
				if (TypeDescriptor.GetProperties(this)[propertyName] == null)
				{
					string msg = "Invalid property name: " + propertyName;

					if (this.ThrowOnInvalidPropertyName)
						throw new Exception(msg);
					else
						Debug.Fail(msg);
				}
			}
		}
	}

	namespace RichTextBoxExt
	{
		using System.IO.Packaging;
		using System.Xml.Linq;

		public static class RichTextBoxHelper
		{
			/// <summary>
			/// Load text snippet to RichTextBox control
			/// </summary>
			/// <param name="rtb"></param>
			/// <param name="text">Text to load</param>
			public static void LoadTextInRichTB(this RichTextBox rtb, string text)
			{
				TextRange range = null;
				MemoryStream ms = null;

				using (ms = new MemoryStream())
				{
					using (StreamWriter streamWriter = new StreamWriter(ms))
					{
						streamWriter.Write(text);
						streamWriter.Flush();
						ms.Seek(0, SeekOrigin.Begin);
						range = new TextRange(rtb.Document.ContentStart, rtb.Document.ContentEnd);
						range.Load(ms, DataFormats.Text);
					}
				}
			}

			/// <summary>
			/// Load text to RichTextBox ontrol from file
			/// </summary>
			/// <param name="RTB"></param>
			/// <param name="fileName"></param>
			public static void LoadTextFromFileToRTB(this RichTextBox RTB, string fileName)
			{
				TextRange range = null;
				FileStream fStream = null;

				if (!string.IsNullOrEmpty(fileName) && File.Exists(fileName))
				{
					using (fStream = new FileStream(fileName, FileMode.OpenOrCreate))
					{
						range = new TextRange(RTB.Document.ContentStart, RTB.Document.ContentEnd);

						range.Load(fStream, DataFormats.Text);
						fStream.Close();
					}
				}
			}

			/// <summary>
			/// Determine if text in RichTextBox is empty
			/// </summary>
			/// <param name="richTB"></param>
			/// <returns>true if empty</returns>
			public static bool IsEmptyRichTB(this RichTextBox richTB)
			{
				TextPointer startPointer = richTB.Document.ContentStart.GetNextInsertionPosition(LogicalDirection.Forward);
				TextPointer endPointer = richTB.Document.ContentEnd.GetNextInsertionPosition(LogicalDirection.Backward);
				if (startPointer.CompareTo(endPointer) == 0)
					return true;
				else
					return false;
			}

			/// <summary>
			/// This method highlights the first word in the RichTextBox
			/// </summary>
			public static void HighlightFirstWord(this RichTextBox MyRTB1)
			{
				TextPointer StartofContent = MyRTB1.Document.ContentStart;
				TextPointer currentPointer = StartofContent.GetNextInsertionPosition(LogicalDirection.Forward);

				if (currentPointer == null)
					return;

				string currentChar = GetCurrentChar(MyRTB1, currentPointer, LogicalDirection.Forward);

				while (currentChar != " " && currentChar != "")
				{
					currentPointer = currentPointer.GetNextInsertionPosition(LogicalDirection.Forward);
					currentChar = GetCurrentChar(MyRTB1, currentPointer, LogicalDirection.Forward);
				}

				System.Windows.Rect StartRect = StartofContent.GetCharacterRect(LogicalDirection.Forward);
				System.Windows.Rect EndRect = currentPointer.GetCharacterRect(LogicalDirection.Forward);
				StartRect.Union(EndRect);
			}

			/// <summary>
			/// Get current char from cursor position
			/// </summary>
			/// <param name="RTB"></param>
			/// <param name="pointer">Text pointer</param>
			/// <param name="direction">Logical direction</param>
			/// <returns>string 'char'</returns>
			public static string GetCurrentChar(this RichTextBox RTB, TextPointer pointer, LogicalDirection direction)
			{
				if (pointer == null)
					return string.Empty;

				TextPointer nextPointer = pointer.GetNextInsertionPosition(direction);
				if (nextPointer != null)
				{
					RTB.Selection.Select(pointer, nextPointer);
					if (RTB.Selection.Text.Length != 0)
						return RTB.Selection.Text[0].ToString();
				}
				return string.Empty;
			}
		}

		/// <summary>
		/// Navigate Words in WPF RichTextBox
		/// </summary>
		public static class WordBreaker
		{
			/// <summary>
			/// Returns a TextRange covering a word containing or following this TextPointer.
			/// </summary>
			/// <remarks>
			/// If this TextPointer is within a word or at start of word, the containing word range is returned.
			/// If this TextPointer is between two words, the following word range is returned.
			/// If this TextPointer is at trailing word boundary, the following word range is returned.
			/// </remarks>
			public static TextRange GetWordRange(TextPointer position)
			{
				TextRange wordRange = null;
				TextPointer wordStartPosition = null;
				TextPointer wordEndPosition = null;

				// Go forward first, to find word end position.
				wordEndPosition = GetPositionAtWordBoundary(position, /*wordBreakDirection*/LogicalDirection.Forward);
				if (wordEndPosition != null)
				{
					// Then travel backwards, to find word start position.
					wordStartPosition = GetPositionAtWordBoundary(wordEndPosition, /*wordBreakDirection*/LogicalDirection.Backward);
				}
				if (wordStartPosition != null && wordEndPosition != null)
				{
					wordRange = new TextRange(wordStartPosition, wordEndPosition);
				}
				return wordRange;
			}

			/// <summary>
			/// 1.  When wordBreakDirection = Forward, returns a position at the end of the word,
			///     i.e. a position with a wordBreak character (space) following it.
			/// 2.  When wordBreakDirection = Backward, returns a position at the start of the word,
			///     i.e. a position with a wordBreak character (space) preceeding it.
			/// 3.  Returns null when there is no workbreak in the requested direction.
			/// </summary>
			private static TextPointer GetPositionAtWordBoundary(TextPointer position, LogicalDirection wordBreakDirection)
			{
				if (!position.IsAtInsertionPosition)
				{
					position = position.GetInsertionPosition(wordBreakDirection);
				}

				TextPointer navigator = position;
				while (navigator != null && !IsPositionNextToWordBreak(navigator, wordBreakDirection))
				{
					navigator = navigator.GetNextInsertionPosition(wordBreakDirection);
				}
				return navigator;
			}

			// Helper for GetPositionAtWordBoundary.
			// Returns true when passed TextPointer is next to a wordBreak in requested direction.
			private static bool IsPositionNextToWordBreak(TextPointer position, LogicalDirection wordBreakDirection)
			{
				bool isAtWordBoundary = false;
				// Skip over any formatting.
				if (position.GetPointerContext(wordBreakDirection) != TextPointerContext.Text)
				{
					position = position.GetInsertionPosition(wordBreakDirection);
				}

				if (position.GetPointerContext(wordBreakDirection) == TextPointerContext.Text)
				{
					LogicalDirection oppositeDirection = (wordBreakDirection == LogicalDirection.Forward) ?
						LogicalDirection.Backward : LogicalDirection.Forward;

					char[] runBuffer = new char[1];
					char[] oppositeRunBuffer = new char[1];

					position.GetTextInRun(wordBreakDirection, runBuffer, /*startIndex*/0, /*count*/1);
					position.GetTextInRun(oppositeDirection, oppositeRunBuffer, /*startIndex*/0, /*count*/1);

					if (runBuffer[0] == ' ' && !(oppositeRunBuffer[0] == ' '))
					{
						isAtWordBoundary = true;
					}
				}
				else
				{
					// If we're not adjacent to text then we always want to consider this position a "word break".  
					// In practice, we're most likely next to an embedded object or a block boundary.
					isAtWordBoundary = true;
				}
				return isAtWordBoundary;
			}
		}


		/// <summary>
		/// This class represents the possible options for search operation.
		/// </summary>
		[Flags]
		public enum FindOptions
		{
			/// <summary>
			/// Perform case-insensitive non-word search.
			/// </summary>
			None = 0x00000000,
			/// <summary>
			/// Perform case-sensitive search.
			/// </summary>
			MatchCase = 0x00000001,
			/// <summary>
			/// Perform the search against whole word.
			/// </summary>
			MatchWholeWord = 0x00000002,
		}

		/// <summary>
		/// This class encapsulates the find and replace operations for<see cref="FlowDocument"/>.
		/// </summary>
		public sealed class RichTBFindReplaceManager
		{
			private FlowDocument m_currentDocument;
			private TextPointer m_currentPosition;

			/// <summary>
			/// Initializes a new instance of the<see cref="FindReplaceManager"/> 
			/// class given the specified<see cref="FlowDocument"/> instance.
			/// </summary>
			/// <param name="inputDocument">the input document</param>
			public RichTBFindReplaceManager(FlowDocument inputDocument)
			{
				if (inputDocument == null)
				{
					throw new ArgumentNullException("documentToFind");
				}

				this.m_currentDocument = inputDocument;
				this.m_currentPosition = inputDocument.ContentStart;
			}

			/// <summary>
			/// Gets and sets the offset position for the<see cref="FindReplaceManager"/>
			/// </summary>
			public TextPointer CurrentTextPosition
			{
				get
				{
					return m_currentPosition;
				}
				set
				{
					if (value == null)
					{
						throw new ArgumentNullException("value");
					}
					if (value.CompareTo(m_currentDocument.ContentStart) < 0 ||
						value.CompareTo(m_currentDocument.ContentEnd) > 0)
					{
						throw new ArgumentOutOfRangeException("value");
					}

					m_currentPosition = value;
				}
			}

			/// <summary>
			/// Find next match of the input string.
			/// </summary>
			/// <param name="input">The string to search for a match.</param>
			/// <param name="findOptions">the search options</param>
			/// <returns>The<see cref="TextRange"/> instance representing the input string.</returns>
			/// <remarks>
			/// This method will advance the<see cref="CurrentTextPosition"/> to next context position.
			/// </remarks>
			public TextRange FindNextString(string input, FindOptions findOptions)
			{
				TextRange textRange = GetTextRangeFromPosition(ref m_currentPosition, input, findOptions);
				return textRange;
			}

			/// <summary>
			/// Finds the corresponding<see cref="TextRange"/> instance 
			/// representing the input string given a specified text pointer position.
			/// </summary>
			/// <param name="position">the current text position</param>
			/// <param name="textToFind">input text</param>
			/// <param name="findOptions">the search option</param>
			/// <returns>
			/// An<see cref="TextRange"/> instance represeneting the matching
			/// string withing the text container.
			/// </returns>
			public TextRange GetTextRangeFromPosition(ref TextPointer position, string input, FindOptions findOptions)
			{
				Boolean matchCase = (findOptions & FindOptions.MatchCase) == FindOptions.MatchCase;
				Boolean matchWholeWord = (findOptions & FindOptions.MatchWholeWord) == FindOptions.MatchWholeWord;

				TextRange textRange = null;

				while (position != null)
				{
					if (position.CompareTo(m_currentDocument.ContentEnd) == 0)
					{
						break;
					}

					if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
					{
						String textRun = position.GetTextInRun(LogicalDirection.Forward);
						StringComparison stringComparison = matchCase ?
							StringComparison.CurrentCulture : StringComparison.CurrentCultureIgnoreCase;
						Int32 indexInRun = textRun.IndexOf(input, stringComparison);

						if (indexInRun >= 0)
						{
							position = position.GetPositionAtOffset(indexInRun);
							TextPointer nextPointer = position.GetPositionAtOffset(input.Length);
							textRange = new TextRange(position, nextPointer);

							if (matchWholeWord)
							{
								if (IsWholeWord(textRange)) // Test if the "textRange" represents a word.
								{
									// If a WholeWord match is found, directly terminate the loop.
									position = position.GetPositionAtOffset(input.Length);
									break;
								}
								else
								{
									// If a WholeWord match is not found, go to next recursion to find it.
									position = position.GetPositionAtOffset(input.Length);
									return GetTextRangeFromPosition(ref position, input, findOptions);
								}
							}
							else
							{
								// If a none-WholeWord match is found, directly terminate the loop.
								position = position.GetPositionAtOffset(input.Length);
								break;
							}
						}
						else
						{
							// If a match is not found, go over to the next context position after the "textRun".
							position = position.GetPositionAtOffset(textRun.Length);
						}
					}
					else
					{
						//If the current position doesn't represent a text context position, go to the next context position.
						// This can effectively ignore the formatting or embed element symbols.
						position = position.GetNextContextPosition(LogicalDirection.Forward);
					}
				}

				return textRange;
			}

			/// <summary>
			/// Within a specified input string, replaces the input string that
			/// match a regular expression pattern with a specified replacement string.
			/// </summary>
			/// <param name="input">The string to search for a match.</param>
			/// <param name="replacement">The replacement string.</param>
			/// <param name="findOptions"> the search options</param>
			/// <returns>The<see cref="TextRange"/> instance representing the replacement string.</returns>
			/// <remarks>
			/// This method will advance the<see cref="CurrentTextPosition"/> to next context position.
			/// </remarks>
			public TextRange ReplaceText(string input, string replacement, FindOptions findOptions)
			{
				TextRange textRange = FindNextString(input, findOptions);
				if (textRange != null)
				{
					textRange.Text = replacement;
				}

				return textRange;
			}

			/// <summary>
			/// Within a specified input string, replaces all the input strings that
			/// match a specified criteria with a specified replacement string.
			/// </summary>
			/// <param name="input">The string to search for a match.</param>
			/// <param name="replacement">The replacement string.</param>
			/// <param name="findOptions"> the search options</param>
			/// <param name="action">the action performed for each match of the input string.</param>
			/// <returns>The number of times the replacement can occur.</returns>
			/// <remarks>
			/// This method will advance the<see cref="CurrentTextPosition"/> to last context position.
			/// </remarks>
			public Int32 ReplaceAllText(string input, string replacement, FindOptions findOptions, Action<TextRange> action)
			{
				Int32 count = 0;
				m_currentPosition = m_currentDocument.ContentStart;
				while (m_currentPosition.CompareTo(m_currentDocument.ContentEnd) < 0)
				{
					TextRange textRange = ReplaceText(input, replacement, findOptions);
					if (textRange != null)
					{
						count++;
						if (action != null)
						{
							action(textRange);
						}
					}
				}

				return count;
			}

			/// <summary>
			/// determines if the specified character is a valid word character.
			/// here only underscores, letters, and digits are considered to be valid.
			/// </summary>
			/// <param name="character">character specified</param>
			/// <returns>Boolean value didicates if the specified character is a valid word character</returns>
			private Boolean IsWordChar(Char character)
			{
				return Char.IsLetterOrDigit(character) || character == '_';
			}

			/// <summary>
			/// Tests if the string within the specified<see cref="TextRange"/>instance is a word.
			/// </summary>
			/// <param name="textRange"><see cref="TextRange"/>instance to test</param>
			/// <returns>test result</returns>
			private Boolean IsWholeWord(TextRange textRange)
			{
				Char[] chars = new Char[1];

				if (textRange.Start.CompareTo(m_currentDocument.ContentStart) == 0 || textRange.Start.IsAtLineStartPosition)
				{
					textRange.End.GetTextInRun(LogicalDirection.Forward, chars, 0, 1);
					return !IsWordChar(chars[0]);
				}
				else if (textRange.End.CompareTo(m_currentDocument.ContentEnd) == 0)
				{
					textRange.Start.GetTextInRun(LogicalDirection.Backward, chars, 0, 1);
					return !IsWordChar(chars[0]);
				}
				else
				{
					textRange.End.GetTextInRun(LogicalDirection.Forward, chars, 0, 1);
					if (!IsWordChar(chars[0]))
					{
						textRange.Start.GetTextInRun(LogicalDirection.Backward, chars, 0, 1);
						return !IsWordChar(chars[0]);
					}
				}

				return false;
			}
		}

		/// <summary>
		/// Open flow document extension class
		/// </summary>
		public static class OpenFlowDocumentExtensions
		{
			/// <summary>
			/// Load word document
			/// </summary>
			/// <param name="flowDoc"></param>
			/// <param name="filename">File path</param>
			public static void LoadWordML(this FlowDocument flowDoc, string filename)
			{
				LoadWord2007ML(flowDoc, filename);
			}


			/// <summary>
			/// Load word document
			/// </summary>
			/// <param name="flowDoc"></param>
			/// <param name="filename">File path</param>
			public static void LoadWord2007ML(FlowDocument flowDoc, string filename)
			{
				XElement wordDoc = null;
				try
				{
					Package package = Package.Open(filename);
					Uri documentUri = new Uri("/word/document.xml", UriKind.Relative);
					PackagePart documentPart = package.GetPart(documentUri);
					wordDoc = XElement.Load(new System.IO.StreamReader(documentPart.GetStream()));
				}
				catch (Exception)
				{
					flowDoc.Blocks.Add(new Paragraph(new Run("File not found or not in correct format (Word 2007)")));
					return;
				}

				XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";

				var paragraphs = from p in wordDoc.Descendants(w + "p")
								 select p;

				foreach (var p in paragraphs)
				{
					var style = from s in p.Descendants(w + "pPr")
								select s;

					var font = (from f in style.Descendants(w + "rFonts")
								select f.FirstAttribute).FirstOrDefault();
					var size = (from s in style.Descendants(w + "sz")
								select s.FirstAttribute).FirstOrDefault();

					Paragraph par = new Paragraph();
					Run r = new Run(p.Value);
					if (font != null)
					{
						FontFamilyConverter converter = new FontFamilyConverter();
						r.FontFamily = (FontFamily)converter.ConvertFrom(font.Value);
					}
					if (size != null)
					{
						r.FontSize = double.Parse(size.Value);
					}
					par.Inlines.Add(r);

					flowDoc.Blocks.Add(par);
				}
			}
		}

	}

	namespace VisualTreeExt
	{
		/// <summary>
		/// Helper methods for UI-related tasks.
		/// </summary>
		public static class TreeHelperExt
		{
			/// <summary>
			/// Finds a parent of a given item on the visual tree.
			/// </summary>
			/// <typeparam name="T">The type of the queried item.</typeparam>
			/// <param name="child">A direct or indirect child of the
			/// queried item.</param>
			/// <returns>The first parent item that matches the submitted
			/// type parameter. If not matching item can be found, a null
			/// reference is being returned.</returns>
			public static T TryFindParent<T>(this DependencyObject child)
				where T : DependencyObject
			{
				//get parent item
				DependencyObject parentObject = GetParentObject(child);

				//we've reached the end of the tree
				if (parentObject == null) return null;

				//check if the parent matches the type we're looking for
				T parent = parentObject as T;
				if (parent != null)
				{
					return parent;
				}
				else
				{
					//use recursion to proceed with next level
					return TryFindParent<T>(parentObject);
				}
			}

			/// <summary>
			/// This method is an alternative to WPF's
			/// <see cref="VisualTreeHelper.GetParent"/> method, which also
			/// supports content elements. Keep in mind that for content element,
			/// this method falls back to the logical tree of the element!
			/// </summary>
			/// <param name="child">The item to be processed.</param>
			/// <returns>The submitted item's parent, if available. Otherwise
			/// null.</returns>
			public static DependencyObject GetParentObject(this DependencyObject child)
			{
				if (child == null) return null;

				//handle content elements separately
				ContentElement contentElement = child as ContentElement;
				if (contentElement != null)
				{
					DependencyObject parent = ContentOperations.GetParent(contentElement);
					if (parent != null) return parent;

					FrameworkContentElement fce = contentElement as FrameworkContentElement;
					return fce != null ? fce.Parent : null;
				}

				//also try searching for parent in framework elements (such as DockPanel, etc)
				FrameworkElement frameworkElement = child as FrameworkElement;
				if (frameworkElement != null)
				{
					DependencyObject parent = frameworkElement.Parent;
					if (parent != null) return parent;
				}

				//if it's not a ContentElement/FrameworkElement, rely on VisualTreeHelper
				return VisualTreeHelper.GetParent(child);
			}


			/// <summary>
			/// Analyzes both visual and logical tree in order to find all elements of a given
			/// type that are descendants of the <paramref name="source"/> item.
			/// </summary>
			/// <typeparam name="T">The type of the queried items.</typeparam>
			/// <param name="source">The root element that marks the source of the search. If the
			/// source is already of the requested type, it will not be included in the result.</param>
			/// <returns>All descendants of <paramref name="source"/> that match the requested type.</returns>
			public static IEnumerable<T> FindChildren<T>(this DependencyObject source) where T : DependencyObject
			{
				if (source != null)
				{
					var childs = GetChildObjects(source);
					foreach (DependencyObject child in childs)
					{
						//analyze if children match the requested type
						if (child != null && child is T)
						{
							yield return (T)child;
						}

						//recurse tree
						foreach (T descendant in FindChildren<T>(child))
						{
							yield return descendant;
						}
					}
				}
			}


			/// <summary>
			/// This method is an alternative to WPF's
			/// <see cref="VisualTreeHelper.GetChild"/> method, which also
			/// supports content elements. Keep in mind that for content elements,
			/// this method falls back to the logical tree of the element.
			/// </summary>
			/// <param name="parent">The item to be processed.</param>
			/// <returns>The submitted item's child elements, if available.</returns>
			public static IEnumerable<DependencyObject> GetChildObjects(this DependencyObject parent)
			{
				if (parent == null) yield break;

				if (parent is ContentElement || parent is FrameworkElement)
				{
					//use the logical tree for content / framework elements
					foreach (object obj in LogicalTreeHelper.GetChildren(parent))
					{
						var depObj = obj as DependencyObject;
						if (depObj != null) yield return (DependencyObject)obj;
					}
				}
				else
				{
					//use the visual tree per default
					int count = VisualTreeHelper.GetChildrenCount(parent);
					for (int i = 0; i < count; i++)
					{
						yield return VisualTreeHelper.GetChild(parent, i);
					}
				}
			}

			/// <summary>
			/// Tries to locate a given item within the visual tree,
			/// starting with the dependency object at a given position. 
			/// </summary>
			/// <typeparam name="T">The type of the element to be found
			/// on the visual tree of the element at the given location.</typeparam>
			/// <param name="reference">The main element which is used to perform
			/// hit testing.</param>
			/// <param name="point">The position to be evaluated on the origin.</param>
			public static T TryFindFromPoint<T>(UIElement reference, Point point)
				where T : DependencyObject
			{
				DependencyObject element = reference.InputHitTest(point) as DependencyObject;
				if (element == null) return null;
				else if (element is T) return (T)element;
				else return TryFindParent<T>(element);
			}
		}

		public static class VisualTreeHlpr
		{
			public static T FindAncestor<T>(DependencyObject rootObj) where T : class
			{
				if (rootObj == null)
					return default(T);

				DependencyObject target = rootObj;
				do
				{
					target = VisualTreeHelper.GetParent(target);
				}
				while (target != null && !(target is T));

				return target as T;
			}

			public static T GetVisualChild<T>(Visual parent) where T : Visual
			{
				T child = default(T);

				int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
				for (int i = 0; i < numVisuals; i++)
				{
					Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
					child = v as T;
					if (child == null)
					{
						child = GetVisualChild<T>(v);
					}
					if (child != null)
					{
						break;
					}
				}
				return child;
			}

			/// <summary>
			/// Find from point specified UI element
			/// </summary>
			/// <typeparam name="T"></typeparam>
			/// <param name="reference"></param>
			/// <param name="point"></param>
			/// <returns></returns>
			public static T TryFindFromPoint<T>(UIElement reference, Point point)
												where T : DependencyObject
			{
				if (reference == null)
					return default(T);

				DependencyObject element = reference.InputHitTest(point) as DependencyObject;
				if (element == null)
					return null;
				else if (element is T)
					return (T)element;
				else
					return TryFindParent<T>(element);
			}

			/// <summary>
			/// Finds a parent of a given item on the visual tree.
			/// </summary>
			/// <typeparam name="T">The type of the queried item.</typeparam>
			/// <param name="child">A direct or indirect child of the
			/// queried item.</param>
			/// <returns>The first parent item that matches the submitted
			/// type parameter. If not matching item can be found, a null
			/// reference is being returned.</returns>
			public static T TryFindParent<T>(this DependencyObject child)
				where T : DependencyObject
			{
				//get parent item
				DependencyObject parentObject = GetParentObject(child);

				//we've reached the end of the tree
				if (parentObject == null)
					return null;

				//check if the parent matches the type we're looking for
				T parent = parentObject as T;
				if (parent != null)
				{
					return parent;
				}
				else
				{
					//use recursion to proceed with next level
					return TryFindParent<T>(parentObject);
				}
			}

			/// <summary>
			/// This method is an alternative to WPF's
			/// <see cref="VisualTreeHelper.GetParent"/> method, which also
			/// supports content elements. Keep in mind that for content element,
			/// this method falls back to the logical tree of the element!
			/// </summary>
			/// <param name="child">The item to be processed.</param>
			/// <returns>The submitted item's parent, if available. Otherwise
			/// null.</returns>
			public static DependencyObject GetParentObject(this DependencyObject child)
			{
				if (child == null)
					return null;
				//handle content elements separately
				ContentElement contentElement = child as ContentElement;
				if (contentElement != null)
				{
					DependencyObject parent = ContentOperations.GetParent(contentElement);
					if (parent != null)
						return parent;
					FrameworkContentElement fce = contentElement as FrameworkContentElement;
					return fce != null ? fce.Parent : null;
				}
				//also try searching for parent in framework elements (such as DockPanel, etc)
				FrameworkElement frameworkElement = child as FrameworkElement;
				if (frameworkElement != null)
				{
					DependencyObject parent = frameworkElement.Parent;
					if (parent != null)
						return parent;
				}
				//if it's not a ContentElement/FrameworkElement, rely on VisualTreeHelper
				return VisualTreeHelper.GetParent(child);
			}

			public static object GetObjectDataFromPoint<T>(T source, Point point) where T : ItemsControl
			{
				if (source == null)
					return default(T);
				UIElement element = source.InputHitTest(point) as UIElement;
				if (element != null)
				{
					object data = DependencyProperty.UnsetValue;
					while (data == DependencyProperty.UnsetValue)
					{
						data = source.ItemContainerGenerator.ItemFromContainer(element);
						if (data == DependencyProperty.UnsetValue)
							element = VisualTreeHelper.GetParent(element) as UIElement;
						if (element == source)
							return null;
					}
					if (data != DependencyProperty.UnsetValue)
						return data;
				}
				return null;
			}
		}
	}

	namespace UriPackExt
	{
		using System.Windows.Resources;
		using System.Windows.Media.Imaging;

		/// <summary>
		/// Simplifies the creation of pack URIs.
		/// </summary>
		public static class Pack
		{
			/// <summary>
			/// Converts a realtive file path into a pack URI.
			/// </summary>
			/// <param name="relativeFile">Path referring to a given file source.</param>
			/// <returns>Pack URI pointing to the referenced file.</returns>
			public static Uri MakePackUri(string relativeFile)
			{
				//get assembly name and pull out the short name.
				Assembly a = typeof(Pack).Assembly;
				string assemblyShortName = a.ToString().Split(',')[0];

				string uriString = string.Format("pack://application:,,,/{0};component/{1}", assemblyShortName, relativeFile);
				return new Uri(uriString);
			}

			/// <summary>
			/// Load image from uri string
			/// </summary>
			/// <param name="relativeUriString"></param>
			/// <returns></returns>
			public static Image LoadImage(string relativeUriString)
			{
				if (string.IsNullOrEmpty(relativeUriString))
					return null;
				// Get the image stream at the specified URI that
				// is relative to the application package root.
				Uri uri = new Uri(relativeUriString, UriKind.Relative);
				StreamResourceInfo sri = Application.GetResourceStream(uri);

				// Convert the stream to an Image object.
				BitmapImage bi = new BitmapImage();
				bi.StreamSource = sri.Stream;
				Image img = new Image();
				img.Source = bi;

				return img;
			}
		}

	}

	namespace WinFormsToWpf
	{
		using System.ComponentModel;
		using System.Windows.Media.Imaging;
		using System.Windows.Interop;
		using System.Runtime.InteropServices;

		/// <summary>
		/// Extension methods to convert images
		/// </summary>
		public static class ExtensionMethods
		{
			/// <summary>
			/// Converts a <see cref="System.Drawing.Image"/> into a WPF <see cref="BitmapSource"/>.
			/// </summary>
			/// <param name="source">The source image.</param>
			/// <returns>A BitmapSource</returns>
			public static BitmapSource ToBitmapSource(this System.Drawing.Image source)
			{
				var bitmap = new System.Drawing.Bitmap(source);
				var bitSrc = bitmap.ToBitmapSource();

				bitmap.Dispose();
				return bitSrc;
			}

			/// <summary>
			/// Converts a <see cref="System.Drawing.Bitmap"/> into a WPF <see cref="BitmapSource"/>.
			/// </summary>
			/// <remarks>Uses GDI to do the conversion. Hence the call to the marshalled DeleteObject.
			/// </remarks>
			/// <param name="source">The source bitmap.</param>
			/// <returns>A BitmapSource</returns>
			public static BitmapSource ToBitmapSource(this System.Drawing.Bitmap source)
			{
				BitmapSource bitSrc;
				IntPtr hBitmap = source.GetHbitmap();

				try
				{
					bitSrc = Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero,
						Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
				}
				catch (Win32Exception)
				{
					bitSrc = null;
				}
				finally
				{
					NativeMethods.DeleteObject(hBitmap);
				}
				return bitSrc;
			}

			/// <summary>
			/// FxCop requires all Marshalled functions to be in a class called NativeMethods.
			/// </summary>
			internal static class NativeMethods
			{
				[DllImport("gdi32.dll")]
				[return: MarshalAs(UnmanagedType.Bool)]
				internal static extern bool DeleteObject(IntPtr hObject);
			}
		}
	}

	namespace XamlExt
	{
		public class MyXamlExtension
		{
			public static void WriteXaml(string path, object objToSave)
			{
				using (TextWriter XamlWriter = File.CreateText(path))
				{
					System.Xaml.XamlServices.Save(XamlWriter, objToSave);
				}
			}

			public static T ReadFromXaml<T>(string path) where T : class
			{
				using (TextReader XamlReader = File.OpenText(path))
				{
					T obj = (T)System.Xaml.XamlServices.Load(XamlReader);
					return obj;
				}
			}
		}

		public static class XamlHelper
		{
			public static string GetXamlDeclaration(object objectToSave)
			{
				StringBuilder outstr = new StringBuilder();
				XmlWriterSettings settings = new XmlWriterSettings();
				settings.Indent = true;
				settings.OmitXmlDeclaration = true;
				XamlDesignerSerializationManager dsm = new XamlDesignerSerializationManager(XmlWriter.Create(outstr, settings));
				//this string need for turning on expression saving mode 
				dsm.XamlWriterMode = XamlWriterMode.Expression;
				XamlWriter.Save(objectToSave, dsm);
				return outstr.ToString();
			}

			public static T ReadXamlFromFile<T>(string filePath)
			{
				if (!File.Exists(filePath))
				{
					return default(T);
				}

				using (StreamReader stream = new StreamReader(filePath, Encoding.UTF8))
				{
					using (StringReader sr = new StringReader(stream.ReadToEnd()))
					{
						XmlReader reader = XmlReader.Create(sr);
						return (T)XamlReader.Load(reader);
					}
				}
			}

			public static T ReadXamlFromContent<T>(string xamlContent)
			{
				if (string.IsNullOrEmpty(xamlContent))
					return default(T);

				using (StringReader sr = new StringReader(xamlContent))
				{
					XmlReader reader = XmlReader.Create(sr);
					return (T)XamlReader.Load(reader);
				}

			}

			public static void WriteXaml(string file, object data)
			{
				if (data == null)
					return;

				if (System.IO.File.Exists(file))
				{
					System.IO.File.Delete(file);
				}

				XmlWriterSettings set = new XmlWriterSettings();
				set.Indent = true;
				set.OmitXmlDeclaration = true;

				using (XmlWriter writer = XmlWriter.Create(file, set))
				{
					XamlWriter.Save(data, writer);
					writer.Flush();
				}
			}
		}
	}

	namespace WebCam
	{
		using System.Threading;
		using System.Runtime.InteropServices;
		using System.Security;
		using Microsoft.Win32;
		using System.Collections;

		public delegate void WebCameraFrameHandler(object sender, WebCameraEventArgs e);

		public class WebCameraEventArgs : EventArgs
		{
			System.Drawing.Bitmap frame;

			public WebCameraEventArgs(System.Drawing.Bitmap frame)
				: base()
			{
				this.frame = frame;
			}

			public System.Drawing.Bitmap Frame
			{
				get { return frame; }
			}
		}

		public class DeviceInfo
		{
			public string Name { get; set; }
			public string Version { get; set; }
			public int Index { get; set; }

			public DeviceInfo(int index)
			{
				this.Name = string.Empty;
				this.Version = string.Empty;
				this.Index = index;
			}

			public DeviceInfo(string name, string version, int index)
			{
				this.Name = name;
				this.Version = version;
				this.Index = index;
			}
		}

		public class ImageGrabberEventArgs : EventArgs
		{
			// Methods
			public ImageGrabberEventArgs() :
				base()
			{
			}

			// Properties
			public System.Drawing.Image DeviceImage
			{
				get;
				set;
			}
		}

		public class ImageGrabber
		{
			// Fields
			private readonly int _hwndParent;
			private readonly ImageGrabberEventArgs args = new ImageGrabberEventArgs();
			private bool bStopped = true;
			private ImageHandler ImageCaptured;
			private const int m_Height = 240;
			private int m_TimeToCapture_milliseconds = 50;
			private const int m_Width = 320;
			private int mCapHwnd;
			private System.Drawing.Image tempImg;
			private IDataObject tempObj;
			private readonly System.Windows.Forms.Timer tmrRefresh;
			public const int WM_CAP_CONNECT = 0x40a;
			public const int WM_CAP_COPY = 0x41e;
			public const int WM_CAP_DISCONNECT = 0x40b;
			public const int WM_CAP_DLG_VIDEOCOMPRESSION = 0x42e;
			public const int WM_CAP_DLG_VIDEODISPLAY = 0x42b;
			public const int WM_CAP_DLG_VIDEOFORMAT = 0x429;
			public const int WM_CAP_DLG_VIDEOSOURCE = 0x42a;
			public const int WM_CAP_GET_FRAME = 0x43c;
			public const int WM_CAP_GET_VIDEOFORMAT = 0x42c;
			public const int WM_CAP_SET_PREVIEW = 0x432;
			public const int WM_CAP_SET_VIDEOFORMAT = 0x42d;
			public const int WM_CAP_START = 0x400;
			public const int WM_USER = 0x400;

			// Events
			public event ImageHandler ImageCaptured2
			{
				add
				{
					ImageHandler handler2;
					ImageHandler imageCaptured = this.ImageCaptured;
					do
					{
						handler2 = imageCaptured;
						ImageHandler handler3 = (ImageHandler)Delegate.Combine(handler2, value);
						imageCaptured = Interlocked.CompareExchange<ImageHandler>(ref this.ImageCaptured, handler3, handler2);
					}
					while (imageCaptured != handler2);
				}
				remove
				{
					ImageHandler handler2;
					ImageHandler imageCaptured = this.ImageCaptured;
					do
					{
						handler2 = imageCaptured;
						ImageHandler handler3 = (ImageHandler)Delegate.Remove(handler2, value);
						imageCaptured = Interlocked.CompareExchange<ImageHandler>(ref this.ImageCaptured, handler3, handler2);
					}
					while (imageCaptured != handler2);
				}
			}

			// Methods
			public ImageGrabber(int hwndParent)
			{
				this._hwndParent = hwndParent;
				this.tmrRefresh = new System.Windows.Forms.Timer();
				this.tmrRefresh.Interval = 100;
				this.tmrRefresh.Tick += new EventHandler(this.tmrRefresh_Tick);
			}

			[DllImport("avicap32.dll")]
			public static extern int capCreateCaptureWindowA(string lpszWindowName, int dwStyle, int X, int Y, int nWidth, int nHeight, int hwndParent, int nID);
			[DllImport("user32")]
			public static extern int CloseClipboard();
			[DllImport("user32")]
			public static extern int EmptyClipboard();
			~ImageGrabber()
			{
				this.Stop();
			}

			[DllImport("user32")]
			public static extern int OpenClipboard(int hWnd);
			[DllImport("user32")]
			public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
			public void Start()
			{
				try
				{
					this.Stop();
					this.mCapHwnd = capCreateCaptureWindowA("WebCap", 0, 0, 0, 320, 240, this._hwndParent, 0);
					System.Windows.Forms.Application.DoEvents();
					SendMessage(this.mCapHwnd, 0x40a, 0, 0);
					SendMessage(this.mCapHwnd, 0x432, 0, 0);
					this.tmrRefresh.Interval = this.m_TimeToCapture_milliseconds;
					this.bStopped = false;
					this.tmrRefresh.Start();
				}
				catch (Exception exception)
				{
					MessageBox.Show("An error ocurred while starting the video capture. Check that your webcamera is connected properly and turned on.\r\n\n" + exception.Message);
					this.Stop();
				}
			}

			public void Stop()
			{
				try
				{
					this.bStopped = true;
					this.tmrRefresh.Stop();
					System.Windows.Forms.Application.DoEvents();
					SendMessage(this.mCapHwnd, 0x40b, 0, 0);
				}
				catch (Exception)
				{
				}
			}

			private void tmrRefresh_Tick(object sender, EventArgs e)
			{
				try
				{
					this.tmrRefresh.Stop();
					SendMessage(this.mCapHwnd, 0x43c, 0, 0);
					SendMessage(this.mCapHwnd, 0x41e, 0, 0);
					if (this.ImageCaptured != null)
					{
						this.tempObj = Clipboard.GetDataObject();
						if (this.tempObj != null)
						{
							this.tempImg = (System.Drawing.Bitmap)this.tempObj.GetData(DataFormats.Bitmap);
						}
						GC.Collect();
						if (this.tempImg == null)
						{
							throw new Exception("");
						}
						this.args.DeviceImage = this.tempImg.GetThumbnailImage(320, 240, null, IntPtr.Zero);
						this.ImageCaptured(this, this.args);
					}
					System.Windows.Forms.Application.DoEvents();
					if (!this.bStopped)
					{
						this.tmrRefresh.Start();
					}
				}
				catch (Exception exception)
				{
					MessageBox.Show("An error ocurred while capturing the video image. The video capture will now be terminated.\r\n\n" + exception.Message);
					this.Stop();
				}
			}

			// Properties
			public int Milliseconds
			{
				get
				{
					return this.m_TimeToCapture_milliseconds;
				}
				set
				{
					this.m_TimeToCapture_milliseconds = value;
				}
			}

			// Nested Types
			public delegate void ImageHandler(object source, ImageGrabberEventArgs e);
		}

		public class WebCamGrabber : IDisposable
		{
			#region Native API
			// Camera API
			const int WM_CAP_START = 1024; // WM_USER

			const int WM_CAP_SET_CALLBACK_FRAME = WM_CAP_START + 5;
			const int WM_CAP_DRIVER_CONNECT = WM_CAP_START + 10;
			const int WM_CAP_DRIVER_DISCONNECT = WM_CAP_START + 11;
			const int WM_CAP_DLG_VIDEODISPLAY = WM_CAP_START + 42;
			const int WM_CAP_SET_VIDEOFORMAT = WM_CAP_START + 45;
			const int WM_CAP_SET_PREVIEW = WM_CAP_START + 50;
			const int WM_CAP_SET_PREVIEWRATE = WM_CAP_START + 52;
			const int WM_CAP_GRAB_FRAME = WM_CAP_START + 60;
			const int WM_CAP_GRAB_FRAME_NOSTOP = WM_CAP_START + 61;

			[DllImport("avicap32.dll")]
			[return: MarshalAs(UnmanagedType.Bool)]
			protected static extern bool capGetDriverDescriptionA(short wDriverIndex, [MarshalAs(UnmanagedType.VBByRefStr)] ref String lpszName,
				int cbName, [MarshalAs(UnmanagedType.VBByRefStr)] ref String lpszVer, int cbVer);

			[DllImport("avicap32.dll", EntryPoint = "capCreateCaptureWindow")]
			[return: MarshalAs(UnmanagedType.SysInt)]
			static extern int capCreateCaptureWindow(string lpszWindowName, int dwStyle, int X, int Y,
				int nWidth, int nHeight, int hwndParent, int nID);

			[DllImport("user32", EntryPoint = "SendMessage")]
			[return: MarshalAs(UnmanagedType.Bool)]
			static extern bool SendMessage(int hWnd, uint wMsg, int wParam, int lParam);

			[DllImport("user32", EntryPoint = "SendMessage")]
			[return: MarshalAs(UnmanagedType.SysInt)]
			static extern int SendBitmapMessage(int hWnd, uint wMsg, int wParam, ref BITMAPINFO lParam);

			[DllImport("user32", EntryPoint = "SendMessage")]
			[return: MarshalAs(UnmanagedType.SysInt)]
			static extern int SendHeaderMessage(int hWnd, uint wMsg, int wParam, CallBackDelegate lParam);

			//This function enable destroy the window child
			[DllImport("user32")]
			protected static extern bool DestroyWindow(int hwnd);

			[StructLayout(LayoutKind.Sequential)]
			public struct VIDEOHEADER
			{
				public IntPtr lpData;
				public uint dwBufferLength;
				public uint dwBytesUsed;
				public uint dwTimeCaptured;
				public uint dwUser;
				public uint dwFlags;
				[MarshalAs(System.Runtime.InteropServices.UnmanagedType.SafeArray)]
				byte[] dwReserved;
			}

			[StructLayout(LayoutKind.Sequential)]
			public struct BITMAPINFOHEADER
			{
				public uint biSize;
				public int biWidth;
				public int biHeight;
				public ushort biPlanes;
				public ushort biBitCount;
				public uint biCompression;
				public uint biSizeImage;
				public int biXPelsPerMeter;
				public int biYPelsPerMeter;
				public uint biClrUsed;
				public uint biClrImportant;
			}

			[StructLayout(LayoutKind.Sequential)]
			public struct BITMAPINFO
			{
				public BITMAPINFOHEADER bmiHeader;
				public int bmiColors;
			}

			#endregion

			delegate void CallBackDelegate(IntPtr hwnd, ref VIDEOHEADER hdr);
			CallBackDelegate delegateFrameCallBack;

			public event WebCameraFrameHandler OnCameraFrame;

			AutoResetEvent autoEvent = new AutoResetEvent(false);
			Thread frameThread = null;

			bool bStart = false;
			int camHwnd, parentHwnd;
			int preferredFPSms, camID;
			int frameWidth, frameHeight;

			public int PreferredFPS
			{
				get { return 1000 / preferredFPSms; }
				set
				{
					if (value == 0)
						preferredFPSms = 0;
					else if (value > 0 && value <= 30)
					{
						preferredFPSms = 1000 / value;
					}
				}
			}

			public int ID
			{
				get { return camID; }
			}

			public int FrameHeight
			{
				get { return frameHeight; }
			}

			public int FrameWidth
			{
				get { return frameWidth; }
			}

			public List<DeviceInfo> Devices
			{
				get;
				private set;
			}

			public WebCamGrabber(int frameWidth, int frameHeight, int preferredFPS, int camID, int parentHwnd)
			{
				Devices = new List<DeviceInfo>();
				GetAllCapturesDevices();

				this.frameWidth = frameWidth;
				this.frameHeight = frameHeight;
				this.parentHwnd = parentHwnd;
				this.camID = camID;
				PreferredFPS = preferredFPS;

				delegateFrameCallBack = FrameCallBack;
			}

			private void FrameCallBack(IntPtr hwnd, ref VIDEOHEADER hdr)
			{
				WebCameraFrameHandler handler = OnCameraFrame;

				if (handler != null)
				{
					System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(frameWidth, frameHeight,
						3 * frameWidth, System.Drawing.Imaging.PixelFormat.Format24bppRgb, hdr.lpData);
					OnCameraFrame(this, new WebCameraEventArgs(bmp));
				}

				// block thread for preferred milleseconds
				if (preferredFPSms == 0)
					autoEvent.WaitOne();
				else
					autoEvent.WaitOne(preferredFPSms, false);
			}

			private void GetAllCapturesDevices()
			{
				if (Devices != null)
					Devices.Clear();

				String dName = "".PadRight(100);
				String dVersion = "".PadRight(100);

				for (short i = 0; i < 10; i++)
				{
					if (capGetDriverDescriptionA(i, ref dName, 100, ref dVersion, 100))
					{
						DeviceInfo d = new DeviceInfo(i);
						d.Name = dName.Trim();
						d.Version = dVersion.Trim();
						Devices.Add(d);
					}
				}
			}

			public void RefreshDevices()
			{
				GetAllCapturesDevices();
			}

			/// <summary>
			/// Allow waiting worker (FrameGrabber) thread to proceed
			/// </summary>
			public void Set()
			{
				autoEvent.Set();
			}

			public void Start()
			{
				try
				{
					camHwnd = capCreateCaptureWindow("WebCam", 0, 0, 0, frameWidth, frameHeight, parentHwnd, camID);

					// connect to the device
					if (SendMessage(camHwnd, WM_CAP_DRIVER_CONNECT, 0, 0))
					{
						BITMAPINFO bInfo = new BITMAPINFO();
						bInfo.bmiHeader = new BITMAPINFOHEADER();
						bInfo.bmiHeader.biSize = (uint)Marshal.SizeOf(bInfo.bmiHeader);
						bInfo.bmiHeader.biWidth = frameWidth;
						bInfo.bmiHeader.biHeight = frameHeight;
						bInfo.bmiHeader.biPlanes = 1;
						bInfo.bmiHeader.biBitCount = 24; // bits per frame, 24 - RGB

						//Enable preview mode. In preview mode, frames are transferred from the 
						//capture hardware to system memory and then displayed in the capture 
						//window using GDI functions.
						SendMessage(camHwnd, WM_CAP_SET_PREVIEW, 1, 0);
						SendMessage(camHwnd, WM_CAP_SET_PREVIEWRATE, 34, 0); // sets the frame display rate in preview mode
						SendBitmapMessage(camHwnd, WM_CAP_SET_VIDEOFORMAT, Marshal.SizeOf(bInfo), ref bInfo);

						frameThread = new Thread(new ThreadStart(this.FrameGrabber));
						bStart = true;       // First, set variable
						frameThread.Priority = ThreadPriority.Lowest;
						frameThread.Start(); // Only then put thread to the queue
					}
					else
						throw new Exception("Cannot connect to Web camera device");
				}
				catch (Exception)
				{
					Stop();
				}
			}

			public void Stop()
			{
				try
				{
					bStart = false;
					Set();
					SendMessage(camHwnd, WM_CAP_DRIVER_DISCONNECT, 0, 0);
				}
				catch { }
			}

			private void FrameGrabber()
			{
				while (bStart) // if worker active thread is still required
				{
					try
					{
						// get the next frame. This is the SLOWEST part of the program
						SendMessage(camHwnd, WM_CAP_GRAB_FRAME_NOSTOP, 0, 0);
						SendHeaderMessage(camHwnd, WM_CAP_SET_CALLBACK_FRAME, 0, delegateFrameCallBack);
					}
					catch (Exception)
					{
						this.Stop();
					}
				}
			}

			public void Dispose()
			{
				this.Stop();
				Devices.Clear();
				Devices = null;
				autoEvent.Close();

				if (frameThread.ThreadState == ThreadState.Running)
					frameThread.Abort();

				frameThread = null;
				GC.SuppressFinalize(this);
			}
		}

		public class VideoCapture
		{

			[StructLayout(LayoutKind.Sequential)]
			public struct BITMAPINFOHEADER
			{
				[MarshalAs(UnmanagedType.I4)]
				public Int32 biSize;
				[MarshalAs(UnmanagedType.I4)]
				public Int32 biWidth;
				[MarshalAs(UnmanagedType.I4)]
				public Int32 biHeight;
				[MarshalAs(UnmanagedType.I2)]
				public short biPlanes;
				[MarshalAs(UnmanagedType.I2)]
				public short biBitCount;
				[MarshalAs(UnmanagedType.I4)]
				public Int32 biCompression;
				[MarshalAs(UnmanagedType.I4)]
				public Int32 biSizeImage;
				[MarshalAs(UnmanagedType.I4)]
				public Int32 biXPelsPerMeter;
				[MarshalAs(UnmanagedType.I4)]
				public Int32 biYPelsPerMeter;
				[MarshalAs(UnmanagedType.I4)]
				public Int32 biClrUsed;
				[MarshalAs(UnmanagedType.I4)]
				public Int32 biClrImportant;
			}

			[StructLayout(LayoutKind.Sequential)]
			public struct BITMAPINFO
			{
				[MarshalAs(UnmanagedType.Struct, SizeConst = 40)]
				public BITMAPINFOHEADER bmiHeader;
				[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
				public Int32[] bmiColors;
			}

			private const int WS_CHILD = 0x40000000;
			private const int WS_VISIBLE = 0x10000000;
			private const int SWP_SHOWWINDOW = 0x0040;
			private const int WM_CAP_START = 0x0400;
			private const int WM_CAP_DRIVER_CONNECT = (WM_CAP_START + 10);
			private const int WM_CAP_DRIVER_DISCONNECT = (WM_CAP_START + 11);
			private const int WM_CAP_SET_PREVIEWRATE = (WM_CAP_START + 52);
			private const int WM_CAP_SET_PREVIEW = (WM_CAP_START + 50);
			private const int WM_CAP_GRAB_FRAME = (WM_CAP_START + 60);
			private const int WM_CAP_GET_VIDEOFORMAT = (WM_CAP_START + 44);

			private IntPtr hCapture = (IntPtr)0;
			private int width = 0;
			private int height = 0;

			public bool CreateCaptureWindow(IntPtr hParent, int x, int y)
			{
				hCapture = capCreateCaptureWindow("", WS_CHILD | WS_VISIBLE, x, y, 32, 24, hParent, 0);
				if ((int)hCapture == 0) { return false; }

				SendMessage(hCapture, WM_CAP_DRIVER_CONNECT, 0, 0);
				GetVideoFormat();
				SetWindowPos(hCapture, 0, x, y, width, height, SWP_SHOWWINDOW);

				return true;
			}

			public void ReleaseCaptureWindow()
			{
				if ((int)hCapture != 0)
				{
					SendMessage(hCapture, WM_CAP_DRIVER_DISCONNECT, 0, 0);
					DestroyWindow(hCapture);
					hCapture = (IntPtr)0;
				}
			}

			public void StartPreview()
			{
				SendMessage(hCapture, WM_CAP_SET_PREVIEWRATE, 15, 0);
				SendMessage(hCapture, WM_CAP_SET_PREVIEW, 1, 0);
			}

			public void StopPreview()
			{
				SendMessage(hCapture, WM_CAP_SET_PREVIEW, 0, 0);
			}

			public void GetFrame()
			{
				SendMessage(hCapture, WM_CAP_GRAB_FRAME, 0, 0);
			}

			private void GetVideoFormat()
			{
				BITMAPINFO buffer = new BITMAPINFO();
				int size = Marshal.SizeOf(typeof(BITMAPINFOHEADER));
				buffer.bmiHeader.biSize = size;

				SendMessage(hCapture, WM_CAP_GET_VIDEOFORMAT,
					size, ref buffer);

				width = buffer.bmiHeader.biWidth;
				height = buffer.bmiHeader.biHeight;
			}

			[DllImport("User32.dll")]
			private static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, ref BITMAPINFO lParam);

			[DllImport("User32.dll")]
			private static extern bool SendMessage(IntPtr hWnd, int wMsg, int wParam, int lParam);

			[DllImport("User32.dll")]
			private static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y,
													int cx, int cy, int wFlags);

			[DllImport("user32.dll")]
			private static extern int DestroyWindow(IntPtr hwnd);

			[DllImport("avicap32.dll")]
			private static extern IntPtr capCreateCaptureWindow(string lpszWindowName, int dwStyle, int x, int y, int nWidth, int nHeight,
																IntPtr hWnd, int nID);

		}

		public class WebCam : IDisposable
		{
			/* Those contants are used to overload the unmanaged code functions
			 * each constant represent a state*/

			private const short WM_CAP = 0x400;
			private const int WM_CAP_DRIVER_CONNECT = 0x40a;
			private const int WM_CAP_DRIVER_DISCONNECT = 0x40b;
			private const int WM_CAP_EDIT_COPY = 0x41e;
			private const int WM_CAP_SET_PREVIEW = 0x432;
			private const int WM_CAP_SET_OVERLAY = 0x433;
			private const int WM_CAP_SET_PREVIEWRATE = 0x434;
			private const int WM_CAP_SET_SCALE = 0x435;
			private const int WS_CHILD = 0x40000000;
			private const int WS_VISIBLE = 0x10000000;
			private const short SWP_NOMOVE = 0x2;
			private short SWP_NOZORDER = 0x4;
			private short HWND_BOTTOM = 1;

			//This function enables enumerate the web cam devices
			[DllImport("avicap32.dll")]
			protected static extern bool capGetDriverDescriptionA(short wDriverIndex, [MarshalAs(UnmanagedType.VBByRefStr)]ref String lpszName,
			   int cbName, [MarshalAs(UnmanagedType.VBByRefStr)] ref String lpszVer, int cbVer);

			//This function enables create a  window child with so that you can display it in a picturebox for example
			[DllImport("avicap32.dll")]
			protected static extern int capCreateCaptureWindowA([MarshalAs(UnmanagedType.VBByRefStr)] ref string lpszWindowName,
				int dwStyle, int x, int y, int nWidth, int nHeight, int hWndParent, int nID);

			//This function enables set changes to the size, position, and Z order of a child window
			[DllImport("user32")]
			protected static extern int SetWindowPos(int hwnd, int hWndInsertAfter, int x, int y, int cx, int cy, int wFlags);

			//This function enables send the specified message to a window or windows
			[DllImport("user32", EntryPoint = "SendMessageA")]
			protected static extern int SendMessage(int hwnd, int wMsg, int wParam, [MarshalAs(UnmanagedType.AsAny)] object lParam);

			//This function enable destroy the window child
			[DllImport("user32")]
			protected static extern bool DestroyWindow(int hwnd);

			// Normal device ID
			int DeviceID = 0;
			// Handle value to preview window
			int hHwnd = 0;
			//The devices list
			ArrayList ListOfDevices = new ArrayList();

			//The picture to be displayed
			public System.Windows.Forms.PictureBox Container
			{
				get;
				set;
			}

			/// <summary>
			/// This function is used to load the list of the devices
			/// </summary>
			public void Load()
			{
				string Name = String.Empty.PadRight(100);
				string Version = String.Empty.PadRight(100);
				bool EndOfDeviceList = false;
				short index = 0;

				// Load name of all avialable devices into the lstDevices .
				do
				{
					// Get Driver name and version
					EndOfDeviceList = capGetDriverDescriptionA(index, ref Name, 100, ref Version, 100);
					// If there was a device add device name to the list
					if (EndOfDeviceList) ListOfDevices.Add(Name.Trim());
					index += 1;
				}
				while (!(EndOfDeviceList == false));
			}

			/// <summary>
			/// Function used to display the output from a video capture device, you need to create
			/// a capture window.
			/// </summary>
			public void OpenConnection()
			{
				string DeviceIndex = Convert.ToString(DeviceID);
				IntPtr oHandle = Container.Handle;

				if (Container == null)
				{
					System.Windows.MessageBox.Show("You should set the container property");
				}

				// Open Preview window in picturebox .
				// Create a child window with capCreateCaptureWindowA so you can display it in a picturebox.

				hHwnd = capCreateCaptureWindowA(ref DeviceIndex, WS_VISIBLE | WS_CHILD, 0, 0, 640, 480, oHandle.ToInt32(), 0);
				// Connect to device
				if (SendMessage(hHwnd, WM_CAP_DRIVER_CONNECT, DeviceID, 0) != 0)
				{
					// Set the preview scale
					SendMessage(hHwnd, WM_CAP_SET_SCALE, -1, 0);
					// Set the preview rate in terms of milliseconds
					SendMessage(hHwnd, WM_CAP_SET_PREVIEWRATE, 66, 0);
					// Start previewing the image from the camera
					SendMessage(hHwnd, WM_CAP_SET_PREVIEW, -1, 0);
					// Resize window to fit in picturebox
					SetWindowPos(hHwnd, HWND_BOTTOM, 0, 0, Container.Height, Container.Width, SWP_NOMOVE | SWP_NOZORDER);
				}
				else
				{
					// Error connecting to device close window
					DestroyWindow(hHwnd);
				}
			}

			/// <summary>
			/// Close windows
			/// </summary>
			void CloseConnection()
			{
				SendMessage(hHwnd, WM_CAP_DRIVER_DISCONNECT, DeviceID, 0);
				// close window
				DestroyWindow(hHwnd);
			}

			/// <summary>
			/// Save Image
			/// </summary>
			public void SaveImage()
			{
				IDataObject data;
				System.Drawing.Image oImage;
				SaveFileDialog sfdImage = new SaveFileDialog();
				sfdImage.Filter = "(*.bmp)|*.bmp";
				// Copy image to clipboard
				SendMessage(hHwnd, WM_CAP_EDIT_COPY, 0, 0);

				// Get image from clipboard and convert it to a bitmap
				data = Clipboard.GetDataObject();
				if (data.GetDataPresent(typeof(System.Drawing.Bitmap)))
				{
					oImage = (System.Drawing.Image)data.GetData(typeof(System.Drawing.Bitmap));
					Container.Image = oImage;
					CloseConnection();
					if (sfdImage.ShowDialog() == true)
					{
						oImage.Save(sfdImage.FileName, System.Drawing.Imaging.ImageFormat.Bmp);
					}
				}
			}

			/// <summary>
			/// This function is used to dispose the connection to the device
			/// </summary>
			#region IDisposable Members

			public void Dispose()
			{
				CloseConnection();
			}
			#endregion
		}

	}
}